summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitpod.yml7
-rw-r--r--.mailmap2
-rw-r--r--README.md2
-rw-r--r--doc/changelog/1.12.0-changelog.rst2
-rw-r--r--doc/changelog/1.20.0-changelog.rst2
-rw-r--r--doc/changelog/1.22.1-changelog.rst47
-rw-r--r--doc/neps/nep-0017-split-out-maskedarray.rst2
-rw-r--r--doc/release/upcoming_changes/15844.new_feature.rst4
-rw-r--r--doc/source/dev/development_workflow.rst4
-rw-r--r--doc/source/reference/random/index.rst2
-rw-r--r--doc/source/reference/random/new-or-different.rst2
-rw-r--r--doc/source/reference/simd/generated_tables/cpu_features.inc30
-rw-r--r--doc/source/release.rst1
-rw-r--r--doc/source/release/1.10.3-notes.rst2
-rw-r--r--doc/source/release/1.11.1-notes.rst2
-rw-r--r--doc/source/release/1.12.1-notes.rst2
-rw-r--r--doc/source/release/1.22.1-notes.rst63
-rw-r--r--doc/source/user/absolute_beginners.rst2
-rw-r--r--environment.yml7
-rw-r--r--numpy/__init__.py5
-rw-r--r--numpy/__init__.pyi8
-rw-r--r--numpy/_pyinstaller/__init__.py0
-rw-r--r--numpy/_pyinstaller/hook-numpy.py40
-rw-r--r--numpy/_pyinstaller/pyinstaller-smoke.py32
-rw-r--r--numpy/_pyinstaller/test_pyinstaller.py35
-rw-r--r--numpy/core/_add_newdocs.py4
-rw-r--r--numpy/core/code_generators/generate_umath.py6
-rw-r--r--numpy/core/fromnumeric.py1
-rw-r--r--numpy/core/include/numpy/ndarraytypes.h2
-rw-r--r--numpy/core/include/numpy/npy_common.h13
-rw-r--r--numpy/core/setup.py8
-rw-r--r--numpy/core/src/_simd/_simd.dispatch.c.src4
-rw-r--r--numpy/core/src/common/npy_cpu_features.c.src20
-rw-r--r--numpy/core/src/common/npy_cpu_features.h6
-rw-r--r--numpy/core/src/common/npy_partition.h.src8
-rw-r--r--numpy/core/src/common/numpy_tag.h34
-rw-r--r--numpy/core/src/common/simd/avx2/math.h12
-rw-r--r--numpy/core/src/common/simd/avx512/math.h12
-rw-r--r--numpy/core/src/common/simd/intdiv.h2
-rw-r--r--numpy/core/src/common/simd/neon/math.h59
-rw-r--r--numpy/core/src/common/simd/sse/math.h55
-rw-r--r--numpy/core/src/common/simd/vsx/math.h12
-rw-r--r--numpy/core/src/multiarray/arraytypes.c.src6
-rw-r--r--numpy/core/src/multiarray/common_dtype.c2
-rw-r--r--numpy/core/src/npysort/heapsort.c.src402
-rw-r--r--numpy/core/src/npysort/heapsort.cpp619
-rw-r--r--numpy/core/src/npysort/mergesort.c.src511
-rw-r--r--numpy/core/src/npysort/mergesort.cpp733
-rw-r--r--numpy/core/src/npysort/npysort_common.h4
-rw-r--r--numpy/core/src/npysort/selection.c.src419
-rw-r--r--numpy/core/src/npysort/selection.cpp645
-rw-r--r--numpy/core/src/npysort/timsort.cpp (renamed from numpy/core/src/npysort/timsort.c.src)1558
-rw-r--r--numpy/core/src/umath/loops.c.src56
-rw-r--r--numpy/core/src/umath/loops.h.src22
-rw-r--r--numpy/core/src/umath/loops_unary_fp.dispatch.c.src26
-rw-r--r--numpy/core/src/umath/simd.inc.src180
-rw-r--r--numpy/core/tests/test_cpu_features.py4
-rw-r--r--numpy/core/tests/test_simd.py31
-rw-r--r--numpy/distutils/ccompiler_opt.py7
-rw-r--r--numpy/distutils/checks/cpu_vsx4.c14
-rw-r--r--numpy/distutils/checks/extra_vsx4_mma.c21
-rw-r--r--numpy/distutils/command/build.py4
-rw-r--r--numpy/distutils/command/build_ext.py30
-rw-r--r--numpy/distutils/tests/test_ccompiler_opt.py12
-rw-r--r--numpy/f2py/capi_maps.py3
-rw-r--r--numpy/f2py/cfuncs.py12
-rwxr-xr-xnumpy/f2py/crackfortran.py22
-rw-r--r--numpy/f2py/tests/src/crackfortran/accesstype.f9013
-rw-r--r--numpy/f2py/tests/test_crackfortran.py9
-rw-r--r--numpy/lib/function_base.py2
-rw-r--r--numpy/lib/polynomial.py2
-rw-r--r--numpy/ma/core.py59
-rw-r--r--numpy/random/mtrand.pyx2
-rw-r--r--numpy/setup.py1
-rw-r--r--numpy/testing/_private/extbuild.py4
-rw-r--r--numpy/typing/tests/data/reveal/lib_function_base.pyi2
-rwxr-xr-xsetup.py7
-rw-r--r--tools/gitpod/Dockerfile2
-rw-r--r--tools/openblas_support.py5
-rwxr-xr-xtools/travis-test.sh2
80 files changed, 3720 insertions, 2296 deletions
diff --git a/.gitpod.yml b/.gitpod.yml
index f9c35fd9b..c46752f10 100644
--- a/.gitpod.yml
+++ b/.gitpod.yml
@@ -6,18 +6,20 @@
image: numpy/numpy-gitpod:latest
tasks:
- - name: Prepare development
+ - name: Prepare development environment
init: |
mkdir -p .vscode
cp tools/gitpod/settings.json .vscode/settings.json
+ rm -f /workspace/numpy/.git/shallow.lock
conda activate numpy-dev
+ git pull --unshallow # need to force this else the prebuild fails
+ git fetch --tags
python setup.py build_ext --inplace
echo "🛠 Completed rebuilding NumPy!! 🛠 "
echo "📖 Building docs 📖 "
cd doc
make html
echo "✨ Pre-build complete! You can close this terminal ✨ "
-
# --------------------------------------------------------
# exposing ports for liveserve
@@ -60,3 +62,4 @@ github:
addBadge: false
# add a label once the prebuild is ready to pull requests (defaults to false)
addLabel: false
+ \ No newline at end of file
diff --git a/.mailmap b/.mailmap
index abd7b31ea..862e3d63c 100644
--- a/.mailmap
+++ b/.mailmap
@@ -364,6 +364,8 @@ Nicholas A. Del Grosso <delgrosso@bio.lmu.de> nickdg <delgrosso@bio.lmu.de>
Nicholas McKibben <nicholas.bgp@gmail.com>
Nick Minkyu Lee <mknicklee@protonmail.com> fivemok <9394929+fivemok@users.noreply.github.com>
Oliver Eberle <oliver_eberle@web.de>
+Omid Rajaei <rajaei.net@gmail.com>
+Omid Rajaei <rajaei.net@gmail.com> <89868505+rajaeinet@users.noreply.github.com>
Ondřej Čertík <ondrej.certik@gmail.com>
Óscar Villellas Guillén <oscar.villellas@continuum.io>
Panos Mavrogiorgos <pmav99@users.noreply.github.com>
diff --git a/README.md b/README.md
index 6be1ee316..0d1750006 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@
[![Powered by NumFOCUS](https://img.shields.io/badge/powered%20by-NumFOCUS-orange.svg?style=flat&colorA=E1523D&colorB=007D8A)](
https://numfocus.org)
-[![Pypi Downloads](https://img.shields.io/pypi/dm/numpy.svg?label=Pypi%20downloads)](
+[![PyPI Downloads](https://img.shields.io/pypi/dm/numpy.svg?label=PyPI%20downloads)](
https://pypi.org/project/numpy/)
[![Conda Downloads](https://img.shields.io/conda/dn/conda-forge/numpy.svg?label=Conda%20downloads)](
https://anaconda.org/conda-forge/numpy)
diff --git a/doc/changelog/1.12.0-changelog.rst b/doc/changelog/1.12.0-changelog.rst
index 2e91f510f..052714374 100644
--- a/doc/changelog/1.12.0-changelog.rst
+++ b/doc/changelog/1.12.0-changelog.rst
@@ -283,7 +283,7 @@ A total of 418 pull requests were merged for this release.
* `#7373 <https://github.com/numpy/numpy/pull/7373>`__: ENH: Add bitwise_and identity
* `#7378 <https://github.com/numpy/numpy/pull/7378>`__: added NumPy logo and separator
* `#7382 <https://github.com/numpy/numpy/pull/7382>`__: MAINT: cleanup np.average
-* `#7385 <https://github.com/numpy/numpy/pull/7385>`__: DOC: note about wheels / windows wheels for pypi
+* `#7385 <https://github.com/numpy/numpy/pull/7385>`__: DOC: note about wheels / windows wheels for PyPI
* `#7386 <https://github.com/numpy/numpy/pull/7386>`__: Added label icon to Travis status
* `#7397 <https://github.com/numpy/numpy/pull/7397>`__: BUG: incorrect type for objects whose __len__ fails
* `#7398 <https://github.com/numpy/numpy/pull/7398>`__: DOC: fix typo
diff --git a/doc/changelog/1.20.0-changelog.rst b/doc/changelog/1.20.0-changelog.rst
index f06bd8a8d..f2af4a7de 100644
--- a/doc/changelog/1.20.0-changelog.rst
+++ b/doc/changelog/1.20.0-changelog.rst
@@ -714,7 +714,7 @@ A total of 716 pull requests were merged for this release.
* `#17440 <https://github.com/numpy/numpy/pull/17440>`__: DOC: Cleaner template for PRs
* `#17442 <https://github.com/numpy/numpy/pull/17442>`__: MAINT: fix exception chaining in format.py
* `#17443 <https://github.com/numpy/numpy/pull/17443>`__: ENH: Warn on unsupported Python 3.10+
-* `#17444 <https://github.com/numpy/numpy/pull/17444>`__: ENH: Add ``Typing :: Typed`` to the PyPi classifier
+* `#17444 <https://github.com/numpy/numpy/pull/17444>`__: ENH: Add ``Typing :: Typed`` to the PyPI classifier
* `#17445 <https://github.com/numpy/numpy/pull/17445>`__: DOC: Fix the references for macros
* `#17447 <https://github.com/numpy/numpy/pull/17447>`__: NEP: update NEP 42 with discussion of type hinting applications
* `#17448 <https://github.com/numpy/numpy/pull/17448>`__: DOC: Remove CoC pages from Sphinx
diff --git a/doc/changelog/1.22.1-changelog.rst b/doc/changelog/1.22.1-changelog.rst
new file mode 100644
index 000000000..3b401c1d2
--- /dev/null
+++ b/doc/changelog/1.22.1-changelog.rst
@@ -0,0 +1,47 @@
+
+Contributors
+============
+
+A total of 14 people contributed to this release. People with a "+" by their
+names contributed a patch for the first time.
+
+* Arryan Singh
+* Bas van Beek
+* Charles Harris
+* Denis Laxalde
+* Isuru Fernando
+* Kevin Sheppard
+* Matthew Barber
+* Matti Picus
+* Melissa Weber Mendonça
+* Mukulika Pahari
+* Omid Rajaei +
+* Pearu Peterson
+* Ralf Gommers
+* Sebastian Berg
+
+Pull requests merged
+====================
+
+A total of 20 pull requests were merged for this release.
+
+* `#20702 <https://github.com/numpy/numpy/pull/20702>`__: MAINT, DOC: Post 1.22.0 release fixes.
+* `#20703 <https://github.com/numpy/numpy/pull/20703>`__: DOC, BUG: Use pngs instead of svgs.
+* `#20704 <https://github.com/numpy/numpy/pull/20704>`__: DOC:Fixed the link on user-guide landing page
+* `#20714 <https://github.com/numpy/numpy/pull/20714>`__: BUG: Restore vc141 support
+* `#20724 <https://github.com/numpy/numpy/pull/20724>`__: BUG: Fix array dimensions solver for multidimensional arguments...
+* `#20725 <https://github.com/numpy/numpy/pull/20725>`__: TYP: change type annotation for `__array_namespace__` to ModuleType
+* `#20726 <https://github.com/numpy/numpy/pull/20726>`__: TYP, MAINT: Allow `ndindex` to accept integer tuples
+* `#20757 <https://github.com/numpy/numpy/pull/20757>`__: BUG: Relax dtype identity check in reductions
+* `#20763 <https://github.com/numpy/numpy/pull/20763>`__: TYP: Allow time manipulation functions to accept `date` and `timedelta`...
+* `#20768 <https://github.com/numpy/numpy/pull/20768>`__: TYP: Relax the type of `ndarray.__array_finalize__`
+* `#20795 <https://github.com/numpy/numpy/pull/20795>`__: MAINT: Raise RuntimeError if setuptools version is too recent.
+* `#20796 <https://github.com/numpy/numpy/pull/20796>`__: BUG, DOC: Fixes SciPy docs build warnings
+* `#20797 <https://github.com/numpy/numpy/pull/20797>`__: DOC: fix OpenBLAS version in release note
+* `#20798 <https://github.com/numpy/numpy/pull/20798>`__: PERF: Optimize array check for bounded 0,1 values
+* `#20805 <https://github.com/numpy/numpy/pull/20805>`__: BUG: Fix that reduce-likes honor out always (and live in the...
+* `#20806 <https://github.com/numpy/numpy/pull/20806>`__: BUG: ``array_api.argsort(descending=True)`` respects relative...
+* `#20807 <https://github.com/numpy/numpy/pull/20807>`__: BUG: Allow integer inputs for pow-related functions in `array_api`
+* `#20814 <https://github.com/numpy/numpy/pull/20814>`__: DOC: Refer to NumPy, not pandas, in main page
+* `#20815 <https://github.com/numpy/numpy/pull/20815>`__: DOC: Update Copyright to 2022 [License]
+* `#20819 <https://github.com/numpy/numpy/pull/20819>`__: BUG: Return correctly shaped inverse indices in array_api set...
diff --git a/doc/neps/nep-0017-split-out-maskedarray.rst b/doc/neps/nep-0017-split-out-maskedarray.rst
index 5cb1c0c39..faad68828 100644
--- a/doc/neps/nep-0017-split-out-maskedarray.rst
+++ b/doc/neps/nep-0017-split-out-maskedarray.rst
@@ -123,7 +123,7 @@ References and Footnotes
.. [1] Subclassing ndarray,
https://docs.scipy.org/doc/numpy/user/basics.subclassing.html
-.. [2] PyPi: maskedarray, https://pypi.org/project/maskedarray/
+.. [2] PyPI: maskedarray, https://pypi.org/project/maskedarray/
Copyright
---------
diff --git a/doc/release/upcoming_changes/15844.new_feature.rst b/doc/release/upcoming_changes/15844.new_feature.rst
new file mode 100644
index 000000000..f2746807b
--- /dev/null
+++ b/doc/release/upcoming_changes/15844.new_feature.rst
@@ -0,0 +1,4 @@
+f2py supports reading access type attributes from derived type statements
+-------------------------------------------------------------------------
+As a result, one does not need to use `public` or `private` statements to
+specify derived type access properties.
diff --git a/doc/source/dev/development_workflow.rst b/doc/source/dev/development_workflow.rst
index 457bcf34a..38f047ec0 100644
--- a/doc/source/dev/development_workflow.rst
+++ b/doc/source/dev/development_workflow.rst
@@ -204,10 +204,10 @@ fragments in your commit message::
``[skip travis]``: skip TravisCI jobs
``[skip azurepipelines]``: skip Azure jobs
-*Note: unfortunately not all CI systems implement this feature well, or at all.
+*Note*: unfortunately not all CI systems implement this feature well, or at all.
CircleCI supports ``ci skip`` but has no command to skip only CircleCI.
Azure chooses to still run jobs with skip commands on PRs, the jobs only get
-skipped on merging to master.*
+skipped on merging to master.
.. _workflow_mailing_list:
diff --git a/doc/source/reference/random/index.rst b/doc/source/reference/random/index.rst
index aaabc9b39..674799d47 100644
--- a/doc/source/reference/random/index.rst
+++ b/doc/source/reference/random/index.rst
@@ -185,7 +185,7 @@ What's New or Different
methods which are 2-10 times faster than NumPy's Box-Muller or inverse CDF
implementations.
* Optional ``dtype`` argument that accepts ``np.float32`` or ``np.float64``
- to produce either single or double prevision uniform random variables for
+ to produce either single or double precision uniform random variables for
select distributions
* Optional ``out`` argument that allows existing arrays to be filled for
select distributions
diff --git a/doc/source/reference/random/new-or-different.rst b/doc/source/reference/random/new-or-different.rst
index a81543926..7a206a2ce 100644
--- a/doc/source/reference/random/new-or-different.rst
+++ b/doc/source/reference/random/new-or-different.rst
@@ -84,7 +84,7 @@ And in more detail:
* The bit generators can be used in downstream projects via
Cython.
* Optional ``dtype`` argument that accepts ``np.float32`` or ``np.float64``
- to produce either single or double prevision uniform random variables for
+ to produce either single or double precision uniform random variables for
select distributions
* Uniforms (`~.Generator.random` and `~.Generator.integers`)
diff --git a/doc/source/reference/simd/generated_tables/cpu_features.inc b/doc/source/reference/simd/generated_tables/cpu_features.inc
index 17d1b4951..7782172d2 100644
--- a/doc/source/reference/simd/generated_tables/cpu_features.inc
+++ b/doc/source/reference/simd/generated_tables/cpu_features.inc
@@ -36,26 +36,28 @@ On IBM/POWER big-endian
.. table::
:align: left
- ======== ================
- Name Implies
- ======== ================
- ``VSX``
- ``VSX2`` ``VSX``
- ``VSX3`` ``VSX`` ``VSX2``
- ======== ================
+ ======== =========================
+ Name Implies
+ ======== =========================
+ ``VSX``
+ ``VSX2`` ``VSX``
+ ``VSX3`` ``VSX`` ``VSX2``
+ ``VSX4`` ``VSX`` ``VSX2`` ``VSX3``
+ ======== =========================
On IBM/POWER little-endian
~~~~~~~~~~~~~~~~~~~~~~~~~~
.. table::
:align: left
- ======== ================
- Name Implies
- ======== ================
- ``VSX`` ``VSX2``
- ``VSX2`` ``VSX``
- ``VSX3`` ``VSX`` ``VSX2``
- ======== ================
+ ======== =========================
+ Name Implies
+ ======== =========================
+ ``VSX`` ``VSX2``
+ ``VSX2`` ``VSX``
+ ``VSX3`` ``VSX`` ``VSX2``
+ ``VSX4`` ``VSX`` ``VSX2`` ``VSX3``
+ ======== =========================
On ARMv7/A32
~~~~~~~~~~~~
diff --git a/doc/source/release.rst b/doc/source/release.rst
index eb6437cf0..fe8027304 100644
--- a/doc/source/release.rst
+++ b/doc/source/release.rst
@@ -6,6 +6,7 @@ Release notes
:maxdepth: 3
1.23.0 <release/1.23.0-notes>
+ 1.22.1 <release/1.22.1-notes>
1.22.0 <release/1.22.0-notes>
1.21.5 <release/1.21.5-notes>
1.21.4 <release/1.21.4-notes>
diff --git a/doc/source/release/1.10.3-notes.rst b/doc/source/release/1.10.3-notes.rst
index 0d4df4ce6..9172f7663 100644
--- a/doc/source/release/1.10.3-notes.rst
+++ b/doc/source/release/1.10.3-notes.rst
@@ -2,4 +2,4 @@
NumPy 1.10.3 Release Notes
==========================
-N/A this release did not happen due to various screwups involving PyPi.
+N/A this release did not happen due to various screwups involving PyPI.
diff --git a/doc/source/release/1.11.1-notes.rst b/doc/source/release/1.11.1-notes.rst
index 6303c32f0..a196502cf 100644
--- a/doc/source/release/1.11.1-notes.rst
+++ b/doc/source/release/1.11.1-notes.rst
@@ -4,7 +4,7 @@ NumPy 1.11.1 Release Notes
Numpy 1.11.1 supports Python 2.6 - 2.7 and 3.2 - 3.5. It fixes bugs and
regressions found in Numpy 1.11.0 and includes several build related
-improvements. Wheels for Linux, Windows, and OSX can be found on pypi.
+improvements. Wheels for Linux, Windows, and OSX can be found on PyPI.
Fixes Merged
============
diff --git a/doc/source/release/1.12.1-notes.rst b/doc/source/release/1.12.1-notes.rst
index f67dab108..09a2e6738 100644
--- a/doc/source/release/1.12.1-notes.rst
+++ b/doc/source/release/1.12.1-notes.rst
@@ -4,7 +4,7 @@ NumPy 1.12.1 Release Notes
NumPy 1.12.1 supports Python 2.7 and 3.4 - 3.6 and fixes bugs and regressions
found in NumPy 1.12.0. In particular, the regression in f2py constant parsing
-is fixed. Wheels for Linux, Windows, and OSX can be found on pypi,
+is fixed. Wheels for Linux, Windows, and OSX can be found on PyPI,
Bugs Fixed
==========
diff --git a/doc/source/release/1.22.1-notes.rst b/doc/source/release/1.22.1-notes.rst
new file mode 100644
index 000000000..0012f199e
--- /dev/null
+++ b/doc/source/release/1.22.1-notes.rst
@@ -0,0 +1,63 @@
+.. currentmodule:: numpy
+
+==========================
+NumPy 1.22.1 Release Notes
+==========================
+
+The NumPy 1.22.1 is a maintenance release that fixes bugs discovered after the
+1.22.0 release. Notable fixes are:
+
+- Fix f2PY docstring problems (SciPy)
+- Fix reduction type problems (AstroPy)
+- Fix various typing bugs.
+
+The Python versions supported for this release are 3.8-3.10.
+
+
+Contributors
+============
+
+A total of 14 people contributed to this release. People with a "+" by their
+names contributed a patch for the first time.
+
+* Arryan Singh
+* Bas van Beek
+* Charles Harris
+* Denis Laxalde
+* Isuru Fernando
+* Kevin Sheppard
+* Matthew Barber
+* Matti Picus
+* Melissa Weber Mendonça
+* Mukulika Pahari
+* Omid Rajaei +
+* Pearu Peterson
+* Ralf Gommers
+* Sebastian Berg
+
+
+Pull requests merged
+====================
+
+A total of 20 pull requests were merged for this release.
+
+* `#20702 <https://github.com/numpy/numpy/pull/20702>`__: MAINT, DOC: Post 1.22.0 release fixes.
+* `#20703 <https://github.com/numpy/numpy/pull/20703>`__: DOC, BUG: Use pngs instead of svgs.
+* `#20704 <https://github.com/numpy/numpy/pull/20704>`__: DOC: Fixed the link on user-guide landing page
+* `#20714 <https://github.com/numpy/numpy/pull/20714>`__: BUG: Restore vc141 support
+* `#20724 <https://github.com/numpy/numpy/pull/20724>`__: BUG: Fix array dimensions solver for multidimensional arguments...
+* `#20725 <https://github.com/numpy/numpy/pull/20725>`__: TYP: change type annotation for ``__array_namespace__`` to ModuleType
+* `#20726 <https://github.com/numpy/numpy/pull/20726>`__: TYP, MAINT: Allow ``ndindex`` to accept integer tuples
+* `#20757 <https://github.com/numpy/numpy/pull/20757>`__: BUG: Relax dtype identity check in reductions
+* `#20763 <https://github.com/numpy/numpy/pull/20763>`__: TYP: Allow time manipulation functions to accept ``date`` and ``timedelta``...
+* `#20768 <https://github.com/numpy/numpy/pull/20768>`__: TYP: Relax the type of ``ndarray.__array_finalize__``
+* `#20795 <https://github.com/numpy/numpy/pull/20795>`__: MAINT: Raise RuntimeError if setuptools version is too recent.
+* `#20796 <https://github.com/numpy/numpy/pull/20796>`__: BUG, DOC: Fixes SciPy docs build warnings
+* `#20797 <https://github.com/numpy/numpy/pull/20797>`__: DOC: fix OpenBLAS version in release note
+* `#20798 <https://github.com/numpy/numpy/pull/20798>`__: PERF: Optimize array check for bounded 0,1 values
+* `#20805 <https://github.com/numpy/numpy/pull/20805>`__: BUG: Fix that reduce-likes honor out always (and live in the...
+* `#20806 <https://github.com/numpy/numpy/pull/20806>`__: BUG: ``array_api.argsort(descending=True)`` respects relative...
+* `#20807 <https://github.com/numpy/numpy/pull/20807>`__: BUG: Allow integer inputs for pow-related functions in ``array_api``
+* `#20814 <https://github.com/numpy/numpy/pull/20814>`__: DOC: Refer to NumPy, not pandas, in main page
+* `#20815 <https://github.com/numpy/numpy/pull/20815>`__: DOC: Update Copyright to 2022 [License]
+* `#20819 <https://github.com/numpy/numpy/pull/20819>`__: BUG: Return correctly shaped inverse indices in array_api set...
diff --git a/doc/source/user/absolute_beginners.rst b/doc/source/user/absolute_beginners.rst
index 2c6882905..cf11c6745 100644
--- a/doc/source/user/absolute_beginners.rst
+++ b/doc/source/user/absolute_beginners.rst
@@ -1588,7 +1588,7 @@ If you created this array "a" ::
.. for doctests
The continuous integration truncates dataframe display without this setting.
- >>> pd.set_option('max_columns', 10)
+ >>> pd.set_option('display.max_columns', 10)
You could create a Pandas dataframe ::
diff --git a/environment.yml b/environment.yml
index 024bee2c7..214a75352 100644
--- a/environment.yml
+++ b/environment.yml
@@ -7,7 +7,7 @@ name: numpy-dev
channels:
- conda-forge
dependencies:
- - python
+ - python=3.9 #need to pin to avoid issues with builds
- cython
- compilers
- openblas
@@ -21,13 +21,14 @@ dependencies:
# For type annotations
- mypy=0.931
# For building docs
- - sphinx=4.1.1
+ - sphinx=4.2.0
+ - sphinx-panels
- numpydoc=1.1.0
- ipython
- scipy
- pandas
- matplotlib
- - pydata-sphinx-theme
+ - pydata-sphinx-theme=0.7.2
- breathe
# For linting
- pycodestyle=2.7.0
diff --git a/numpy/__init__.py b/numpy/__init__.py
index e8d1820a1..abe53fe9a 100644
--- a/numpy/__init__.py
+++ b/numpy/__init__.py
@@ -413,6 +413,11 @@ else:
# it is tidier organized.
core.multiarray._multiarray_umath._reload_guard()
+ # Tell PyInstaller where to find hook-numpy.py
+ def _pyinstaller_hooks_dir():
+ from pathlib import Path
+ return [str(Path(__file__).with_name("_pyinstaller").resolve())]
+
# get the version using versioneer
from .version import __version__, git_revision as __git_version__
diff --git a/numpy/__init__.pyi b/numpy/__init__.pyi
index 8e92e0f42..92f98a801 100644
--- a/numpy/__init__.pyi
+++ b/numpy/__init__.pyi
@@ -1451,13 +1451,13 @@ class ndarray(_ArrayOrScalarCommon, Generic[_ShapeType, _DType_co]):
def size(self) -> int: ...
@property
def real(
- self: NDArray[_SupportsReal[_ScalarType]], # type: ignore[type-var]
+ self: ndarray[_ShapeType, dtype[_SupportsReal[_ScalarType]]], # type: ignore[type-var]
) -> ndarray[_ShapeType, _dtype[_ScalarType]]: ...
@real.setter
def real(self, value: ArrayLike) -> None: ...
@property
def imag(
- self: NDArray[_SupportsImag[_ScalarType]], # type: ignore[type-var]
+ self: ndarray[_ShapeType, dtype[_SupportsImag[_ScalarType]]], # type: ignore[type-var]
) -> ndarray[_ShapeType, _dtype[_ScalarType]]: ...
@imag.setter
def imag(self, value: ArrayLike) -> None: ...
@@ -3673,6 +3673,8 @@ class memmap(ndarray[_ShapeType, _DType_co]):
) -> Any: ...
def flush(self) -> None: ...
+# TODO: Add a mypy plugin for managing functions whose output type is dependant
+# on the literal value of some sort of signature (e.g. `einsum` and `vectorize`)
class vectorize:
pyfunc: Callable[..., Any]
cache: bool
@@ -3689,7 +3691,7 @@ class vectorize:
cache: bool = ...,
signature: None | str = ...,
) -> None: ...
- def __call__(self, *args: Any, **kwargs: Any) -> NDArray[Any]: ...
+ def __call__(self, *args: Any, **kwargs: Any) -> Any: ...
class poly1d:
@property
diff --git a/numpy/_pyinstaller/__init__.py b/numpy/_pyinstaller/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/numpy/_pyinstaller/__init__.py
diff --git a/numpy/_pyinstaller/hook-numpy.py b/numpy/_pyinstaller/hook-numpy.py
new file mode 100644
index 000000000..a08b7c963
--- /dev/null
+++ b/numpy/_pyinstaller/hook-numpy.py
@@ -0,0 +1,40 @@
+"""This hook should collect all binary files and any hidden modules that numpy
+needs.
+
+Our (some-what inadequate) docs for writing PyInstaller hooks are kept here:
+https://pyinstaller.readthedocs.io/en/stable/hooks.html
+
+"""
+from PyInstaller.compat import is_conda, is_pure_conda
+from PyInstaller.utils.hooks import collect_dynamic_libs, is_module_satisfies
+
+# Collect all DLLs inside numpy's installation folder, dump them into built
+# app's root.
+binaries = collect_dynamic_libs("numpy", ".")
+
+# If using Conda without any non-conda virtual environment manager:
+if is_pure_conda:
+ # Assume running the NumPy from Conda-forge and collect it's DLLs from the
+ # communal Conda bin directory. DLLs from NumPy's dependencies must also be
+ # collected to capture MKL, OpenBlas, OpenMP, etc.
+ from PyInstaller.utils.hooks import conda_support
+ datas = conda_support.collect_dynamic_libs("numpy", dependencies=True)
+
+# Submodules PyInstaller cannot detect (probably because they are only imported
+# by extension modules, which PyInstaller cannot read).
+hiddenimports = ['numpy.core._dtype_ctypes']
+if is_conda:
+ hiddenimports.append("six")
+
+# Remove testing and building code and packages that are referenced throughout
+# NumPy but are not really dependencies.
+excludedimports = [
+ "scipy",
+ "pytest",
+ "nose",
+ "f2py",
+ "setuptools",
+ "numpy.f2py",
+ "distutils",
+ "numpy.distutils",
+]
diff --git a/numpy/_pyinstaller/pyinstaller-smoke.py b/numpy/_pyinstaller/pyinstaller-smoke.py
new file mode 100644
index 000000000..1c9f78ae3
--- /dev/null
+++ b/numpy/_pyinstaller/pyinstaller-smoke.py
@@ -0,0 +1,32 @@
+"""A crude *bit of everything* smoke test to verify PyInstaller compatibility.
+
+PyInstaller typically goes wrong by forgetting to package modules, extension
+modules or shared libraries. This script should aim to touch as many of those
+as possible in an attempt to trip a ModuleNotFoundError or a DLL load failure
+due to an uncollected resource. Missing resources are unlikely to lead to
+arithmitic errors so there's generally no need to verify any calculation's
+output - merely that it made it to the end OK. This script should not
+explicitly import any of numpy's submodules as that gives PyInstaller undue
+hints that those submodules exist and should be collected (accessing implicitly
+loaded submodules is OK).
+
+"""
+import numpy as np
+
+a = np.arange(1., 10.).reshape((3, 3)) % 5
+np.linalg.det(a)
+a @ a
+a @ a.T
+np.linalg.inv(a)
+np.sin(np.exp(a))
+np.linalg.svd(a)
+np.linalg.eigh(a)
+
+np.unique(np.random.randint(0, 10, 100))
+np.sort(np.random.uniform(0, 10, 100))
+
+np.fft.fft(np.exp(2j * np.pi * np.arange(8) / 8))
+np.ma.masked_array(np.arange(10), np.random.rand(10) < .5).sum()
+np.polynomial.Legendre([7, 8, 9]).roots()
+
+print("I made it!")
diff --git a/numpy/_pyinstaller/test_pyinstaller.py b/numpy/_pyinstaller/test_pyinstaller.py
new file mode 100644
index 000000000..a9061da19
--- /dev/null
+++ b/numpy/_pyinstaller/test_pyinstaller.py
@@ -0,0 +1,35 @@
+import subprocess
+from pathlib import Path
+
+import pytest
+
+
+# PyInstaller has been very unproactive about replacing 'imp' with 'importlib'.
+@pytest.mark.filterwarnings('ignore::DeprecationWarning')
+# It also leaks io.BytesIO()s.
+@pytest.mark.filterwarnings('ignore::ResourceWarning')
+@pytest.mark.parametrize("mode", ["--onedir", "--onefile"])
+@pytest.mark.slow
+def test_pyinstaller(mode, tmp_path):
+ """Compile and run pyinstaller-smoke.py using PyInstaller."""
+
+ pyinstaller_cli = pytest.importorskip("PyInstaller.__main__").run
+
+ source = Path(__file__).with_name("pyinstaller-smoke.py").resolve()
+ args = [
+ # Place all generated files in ``tmp_path``.
+ '--workpath', str(tmp_path / "build"),
+ '--distpath', str(tmp_path / "dist"),
+ '--specpath', str(tmp_path),
+ mode,
+ str(source),
+ ]
+ pyinstaller_cli(args)
+
+ if mode == "--onefile":
+ exe = tmp_path / "dist" / source.stem
+ else:
+ exe = tmp_path / "dist" / source.stem / source.stem
+
+ p = subprocess.run([str(exe)], check=True, stdout=subprocess.PIPE)
+ assert p.stdout.strip() == b"I made it!"
diff --git a/numpy/core/_add_newdocs.py b/numpy/core/_add_newdocs.py
index 7081f9a59..1bbacad45 100644
--- a/numpy/core/_add_newdocs.py
+++ b/numpy/core/_add_newdocs.py
@@ -2943,7 +2943,7 @@ add_newdoc('numpy.core.multiarray', 'ndarray', ('any',
add_newdoc('numpy.core.multiarray', 'ndarray', ('argmax',
"""
- a.argmax(axis=None, out=None)
+ a.argmax(axis=None, out=None, *, keepdims=False)
Return indices of the maximum values along the given axis.
@@ -2958,7 +2958,7 @@ add_newdoc('numpy.core.multiarray', 'ndarray', ('argmax',
add_newdoc('numpy.core.multiarray', 'ndarray', ('argmin',
"""
- a.argmin(axis=None, out=None)
+ a.argmin(axis=None, out=None, *, keepdims=False)
Return indices of the minimum values along the given axis.
diff --git a/numpy/core/code_generators/generate_umath.py b/numpy/core/code_generators/generate_umath.py
index 054150b28..b11504c03 100644
--- a/numpy/core/code_generators/generate_umath.py
+++ b/numpy/core/code_generators/generate_umath.py
@@ -844,7 +844,7 @@ defdict = {
docstrings.get('numpy.core.umath.trunc'),
None,
TD('e', f='trunc', astype={'e': 'f'}),
- TD(inexactvec, simd=[('fma', 'fd'), ('avx512f', 'fd')]),
+ TD(inexactvec, dispatch=[('loops_unary_fp', 'fd')]),
TD('fdg', f='trunc'),
TD(O, f='npy_ObjectTrunc'),
),
@@ -860,7 +860,7 @@ defdict = {
docstrings.get('numpy.core.umath.floor'),
None,
TD('e', f='floor', astype={'e': 'f'}),
- TD(inexactvec, simd=[('fma', 'fd'), ('avx512f', 'fd')]),
+ TD(inexactvec, dispatch=[('loops_unary_fp', 'fd')]),
TD('fdg', f='floor'),
TD(O, f='npy_ObjectFloor'),
),
@@ -869,7 +869,7 @@ defdict = {
docstrings.get('numpy.core.umath.rint'),
None,
TD('e', f='rint', astype={'e': 'f'}),
- TD(inexactvec, simd=[('fma', 'fd'), ('avx512f', 'fd')]),
+ TD(inexactvec, dispatch=[('loops_unary_fp', 'fd')]),
TD('fdg' + cmplx, f='rint'),
TD(P, f='rint'),
),
diff --git a/numpy/core/fromnumeric.py b/numpy/core/fromnumeric.py
index f26f306fa..0ec4f7687 100644
--- a/numpy/core/fromnumeric.py
+++ b/numpy/core/fromnumeric.py
@@ -3408,6 +3408,7 @@ def mean(a, axis=None, dtype=None, out=None, keepdims=np._NoValue, *,
0.55000000074505806 # may vary
Specifying a where argument:
+
>>> a = np.array([[5, 9, 13], [14, 10, 12], [11, 15, 19]])
>>> np.mean(a)
12.0
diff --git a/numpy/core/include/numpy/ndarraytypes.h b/numpy/core/include/numpy/ndarraytypes.h
index 47d063178..35d82ec03 100644
--- a/numpy/core/include/numpy/ndarraytypes.h
+++ b/numpy/core/include/numpy/ndarraytypes.h
@@ -87,7 +87,7 @@ enum NPY_TYPES { NPY_BOOL=0,
/* The number of types not including the new 1.6 types */
NPY_NTYPES_ABI_COMPATIBLE=21
};
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && !defined(__clang__)
#pragma deprecated(NPY_CHAR)
#endif
diff --git a/numpy/core/include/numpy/npy_common.h b/numpy/core/include/numpy/npy_common.h
index 88794ca07..2bcc45e4f 100644
--- a/numpy/core/include/numpy/npy_common.h
+++ b/numpy/core/include/numpy/npy_common.h
@@ -131,9 +131,10 @@
#endif
#endif
-#if defined(_MSC_VER)
- #define NPY_INLINE __inline
-#elif defined(__GNUC__)
+#if defined(_MSC_VER) && !defined(__clang__)
+ #define NPY_INLINE __inline
+/* clang included here to handle clang-cl on Windows */
+#elif defined(__GNUC__) || defined(__clang__)
#if defined(__STRICT_ANSI__)
#define NPY_INLINE __inline__
#else
@@ -180,12 +181,6 @@
defined(__MINGW32__) || defined(__MINGW64__)
#include <io.h>
-/* mingw based on 3.4.5 has lseek but not ftell/fseek */
-#if defined(__MINGW32__) || defined(__MINGW64__)
-extern int __cdecl _fseeki64(FILE *, long long, int);
-extern long long __cdecl _ftelli64(FILE *);
-#endif
-
#define npy_fseek _fseeki64
#define npy_ftell _ftelli64
#define npy_lseek _lseeki64
diff --git a/numpy/core/setup.py b/numpy/core/setup.py
index 22cac1e9a..c97747606 100644
--- a/numpy/core/setup.py
+++ b/numpy/core/setup.py
@@ -947,12 +947,12 @@ def configuration(parent_package='',top_path=None):
join('src', 'multiarray', 'vdot.c'),
join('src', 'common', 'npy_sort.h.src'),
join('src', 'npysort', 'quicksort.c.src'),
- join('src', 'npysort', 'mergesort.c.src'),
- join('src', 'npysort', 'timsort.c.src'),
- join('src', 'npysort', 'heapsort.c.src'),
+ join('src', 'npysort', 'mergesort.cpp'),
+ join('src', 'npysort', 'timsort.cpp'),
+ join('src', 'npysort', 'heapsort.cpp'),
join('src', 'npysort', 'radixsort.cpp'),
join('src', 'common', 'npy_partition.h.src'),
- join('src', 'npysort', 'selection.c.src'),
+ join('src', 'npysort', 'selection.cpp'),
join('src', 'common', 'npy_binsearch.h'),
join('src', 'npysort', 'binsearch.cpp'),
]
diff --git a/numpy/core/src/_simd/_simd.dispatch.c.src b/numpy/core/src/_simd/_simd.dispatch.c.src
index 84de9a059..fabec069c 100644
--- a/numpy/core/src/_simd/_simd.dispatch.c.src
+++ b/numpy/core/src/_simd/_simd.dispatch.c.src
@@ -381,7 +381,7 @@ SIMD_IMPL_INTRIN_1(sumup_@sfx@, @esfx@, v@sfx@)
***************************/
#if @fp_only@
/**begin repeat1
- * #intrin = sqrt, recip, abs, square, ceil, trunc#
+ * #intrin = sqrt, recip, abs, square, rint, ceil, trunc, floor#
*/
SIMD_IMPL_INTRIN_1(@intrin@_@sfx@, v@sfx@, v@sfx@)
/**end repeat1**/
@@ -615,7 +615,7 @@ SIMD_INTRIN_DEF(sumup_@sfx@)
***************************/
#if @fp_only@
/**begin repeat1
- * #intrin = sqrt, recip, abs, square, ceil, trunc#
+ * #intrin = sqrt, recip, abs, square, rint, ceil, trunc, floor#
*/
SIMD_INTRIN_DEF(@intrin@_@sfx@)
/**end repeat1**/
diff --git a/numpy/core/src/common/npy_cpu_features.c.src b/numpy/core/src/common/npy_cpu_features.c.src
index 1385220f9..ff4f9f60a 100644
--- a/numpy/core/src/common/npy_cpu_features.c.src
+++ b/numpy/core/src/common/npy_cpu_features.c.src
@@ -61,7 +61,7 @@ npy_cpu_features_dict(void)
* AVX512VPOPCNTDQ, AVX512VL, AVX512BW, AVX512DQ, AVX512VNNI,
* AVX512IFMA, AVX512VBMI, AVX512VBMI2, AVX512BITALG,
* AVX512_KNL, AVX512_KNM, AVX512_SKX, AVX512_CLX, AVX512_CNL, AVX512_ICL,
- * VSX, VSX2, VSX3,
+ * VSX, VSX2, VSX3, VSX4,
* VX, VXE, VXE2,
* NEON, NEON_FP16, NEON_VFPV4, ASIMD, FPHP, ASIMDHP, ASIMDDP, ASIMDFHM#
*/
@@ -474,9 +474,15 @@ npy__cpu_init_features(void)
#ifndef AT_HWCAP2
#define AT_HWCAP2 26
#endif
+ #ifndef PPC_FEATURE2_ARCH_2_07
+ #define PPC_FEATURE2_ARCH_2_07 0x80000000
+ #endif
#ifndef PPC_FEATURE2_ARCH_3_00
#define PPC_FEATURE2_ARCH_3_00 0x00800000
#endif
+ #ifndef PPC_FEATURE2_ARCH_3_1
+ #define PPC_FEATURE2_ARCH_3_1 0x00040000
+ #endif
#endif
static void
@@ -489,15 +495,18 @@ npy__cpu_init_features(void)
return;
hwcap = getauxval(AT_HWCAP2);
- if (hwcap & PPC_FEATURE2_ARCH_3_00)
+ if (hwcap & PPC_FEATURE2_ARCH_3_1)
{
npy__cpu_have[NPY_CPU_FEATURE_VSX] =
npy__cpu_have[NPY_CPU_FEATURE_VSX2] =
- npy__cpu_have[NPY_CPU_FEATURE_VSX3] = 1;
+ npy__cpu_have[NPY_CPU_FEATURE_VSX3] =
+ npy__cpu_have[NPY_CPU_FEATURE_VSX4] = 1;
return;
}
- npy__cpu_have[NPY_CPU_FEATURE_VSX2] = (hwcap & PPC_FEATURE2_ARCH_2_07) != 0;
npy__cpu_have[NPY_CPU_FEATURE_VSX] = 1;
+ npy__cpu_have[NPY_CPU_FEATURE_VSX2] = (hwcap & PPC_FEATURE2_ARCH_2_07) != 0;
+ npy__cpu_have[NPY_CPU_FEATURE_VSX3] = (hwcap & PPC_FEATURE2_ARCH_3_00) != 0;
+ npy__cpu_have[NPY_CPU_FEATURE_VSX4] = (hwcap & PPC_FEATURE2_ARCH_3_1) != 0;
// TODO: AIX, FreeBSD
#else
npy__cpu_have[NPY_CPU_FEATURE_VSX] = 1;
@@ -507,6 +516,9 @@ npy__cpu_init_features(void)
#ifdef NPY_HAVE_VSX3
npy__cpu_have[NPY_CPU_FEATURE_VSX3] = 1;
#endif
+ #ifdef NPY_HAVE_VSX4
+ npy__cpu_have[NPY_CPU_FEATURE_VSX4] = 1;
+ #endif
#endif
}
diff --git a/numpy/core/src/common/npy_cpu_features.h b/numpy/core/src/common/npy_cpu_features.h
index 1f52a445d..3d5f2e75c 100644
--- a/numpy/core/src/common/npy_cpu_features.h
+++ b/numpy/core/src/common/npy_cpu_features.h
@@ -65,6 +65,8 @@ enum npy_cpu_features
NPY_CPU_FEATURE_VSX2 = 201,
// POWER9
NPY_CPU_FEATURE_VSX3 = 202,
+ // POWER10
+ NPY_CPU_FEATURE_VSX4 = 203,
// ARM
NPY_CPU_FEATURE_NEON = 300,
@@ -167,8 +169,8 @@ npy_cpu_baseline_list(void);
* On x64: ['SSSE3', 'SSE41', 'POPCNT', 'SSE42', 'AVX', 'F16C', 'FMA3', 'AVX2', 'AVX512F', ...]
* On armhf: ['NEON', 'NEON_FP16', 'NEON_VPFV4', 'ASIMD', 'ASIMDHP', 'ASIMDDP', 'ASIMDFHM']
* On aarch64: ['ASIMDHP', 'ASIMDDP', 'ASIMDFHM']
- * On ppc64: ['VSX', 'VSX2', 'VSX3']
- * On ppc64le: ['VSX3']
+ * On ppc64: ['VSX', 'VSX2', 'VSX3', 'VSX4']
+ * On ppc64le: ['VSX3', 'VSX4']
* On s390x: ['VX', 'VXE', VXE2]
* On any other arch or if the optimization is disabled: []
*/
diff --git a/numpy/core/src/common/npy_partition.h.src b/numpy/core/src/common/npy_partition.h.src
index 72c2095f1..5ba652b41 100644
--- a/numpy/core/src/common/npy_partition.h.src
+++ b/numpy/core/src/common/npy_partition.h.src
@@ -28,6 +28,10 @@
#define NPY_MAX_PIVOT_STACK 50
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/**begin repeat
*
* #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG,
@@ -56,6 +60,10 @@ NPY_NO_EXPORT int aintroselect_@suff@(@type@ *v, npy_intp* tosort, npy_intp num,
/**end repeat**/
+#ifdef __cplusplus
+}
+#endif
+
typedef struct {
int typenum;
PyArray_PartitionFunc * part[NPY_NSELECTS];
diff --git a/numpy/core/src/common/numpy_tag.h b/numpy/core/src/common/numpy_tag.h
index 60e9b02cd..ee0c36cac 100644
--- a/numpy/core/src/common/numpy_tag.h
+++ b/numpy/core/src/common/numpy_tag.h
@@ -220,6 +220,40 @@ struct timedelta_tag : date_tag {
}
};
+struct string_tag {
+ using type = npy_char;
+ static constexpr NPY_TYPES type_value = NPY_STRING;
+ static int less(type const* a, type const* b, size_t len) {
+ return STRING_LT(a, b, len);
+ }
+ static int less_equal(type const* a, type const* b, size_t len) {
+ return !less(b, a, len);
+ }
+ static void swap(type* a, type* b, size_t len) {
+ STRING_SWAP(a, b, len);
+ }
+ static void copy(type * a, type const* b, size_t len) {
+ STRING_COPY(a, b, len);
+ }
+};
+
+struct unicode_tag {
+ using type = npy_ucs4;
+ static constexpr NPY_TYPES type_value = NPY_UNICODE;
+ static int less(type const* a, type const* b, size_t len) {
+ return UNICODE_LT(a, b, len);
+ }
+ static int less_equal(type const* a, type const* b, size_t len) {
+ return !less(b, a, len);
+ }
+ static void swap(type* a, type* b, size_t len) {
+ UNICODE_SWAP(a, b, len);
+ }
+ static void copy(type * a, type const* b, size_t len) {
+ UNICODE_COPY(a, b, len);
+ }
+};
+
} // namespace npy
#endif
diff --git a/numpy/core/src/common/simd/avx2/math.h b/numpy/core/src/common/simd/avx2/math.h
index ec15e50e1..deaf4ad11 100644
--- a/numpy/core/src/common/simd/avx2/math.h
+++ b/numpy/core/src/common/simd/avx2/math.h
@@ -42,7 +42,7 @@ NPY_FINLINE npyv_f64 npyv_square_f64(npyv_f64 a)
#define npyv_max_f64 _mm256_max_pd
// Maximum, supports IEEE floating-point arithmetic (IEC 60559),
// - If one of the two vectors contains NaN, the equivalent element of the other vector is set
-// - Only if both corresponded elements are NaN, NaN is set.
+// - Only if both corresponded elements are NaN, NaN is set.
NPY_FINLINE npyv_f32 npyv_maxp_f32(npyv_f32 a, npyv_f32 b)
{
__m256 nn = _mm256_cmp_ps(b, b, _CMP_ORD_Q);
@@ -76,7 +76,7 @@ NPY_FINLINE npyv_s64 npyv_max_s64(npyv_s64 a, npyv_s64 b)
#define npyv_min_f64 _mm256_min_pd
// Minimum, supports IEEE floating-point arithmetic (IEC 60559),
// - If one of the two vectors contains NaN, the equivalent element of the other vector is set
-// - Only if both corresponded elements are NaN, NaN is set.
+// - Only if both corresponded elements are NaN, NaN is set.
NPY_FINLINE npyv_f32 npyv_minp_f32(npyv_f32 a, npyv_f32 b)
{
__m256 nn = _mm256_cmp_ps(b, b, _CMP_ORD_Q);
@@ -105,6 +105,10 @@ NPY_FINLINE npyv_s64 npyv_min_s64(npyv_s64 a, npyv_s64 b)
return _mm256_blendv_epi8(a, b, _mm256_cmpgt_epi64(a, b));
}
+// round to nearest intger even
+#define npyv_rint_f32(A) _mm256_round_ps(A, _MM_FROUND_TO_NEAREST_INT)
+#define npyv_rint_f64(A) _mm256_round_pd(A, _MM_FROUND_TO_NEAREST_INT)
+
// ceil
#define npyv_ceil_f32 _mm256_ceil_ps
#define npyv_ceil_f64 _mm256_ceil_pd
@@ -113,4 +117,8 @@ NPY_FINLINE npyv_s64 npyv_min_s64(npyv_s64 a, npyv_s64 b)
#define npyv_trunc_f32(A) _mm256_round_ps(A, _MM_FROUND_TO_ZERO)
#define npyv_trunc_f64(A) _mm256_round_pd(A, _MM_FROUND_TO_ZERO)
+// floor
+#define npyv_floor_f32 _mm256_floor_ps
+#define npyv_floor_f64 _mm256_floor_pd
+
#endif // _NPY_SIMD_AVX2_MATH_H
diff --git a/numpy/core/src/common/simd/avx512/math.h b/numpy/core/src/common/simd/avx512/math.h
index f30e50ad0..5a6cb6dcd 100644
--- a/numpy/core/src/common/simd/avx512/math.h
+++ b/numpy/core/src/common/simd/avx512/math.h
@@ -51,7 +51,7 @@ NPY_FINLINE npyv_f64 npyv_square_f64(npyv_f64 a)
#define npyv_max_f64 _mm512_max_pd
// Maximum, supports IEEE floating-point arithmetic (IEC 60559),
// - If one of the two vectors contains NaN, the equivalent element of the other vector is set
-// - Only if both corresponded elements are NaN, NaN is set.
+// - Only if both corresponded elements are NaN, NaN is set.
NPY_FINLINE npyv_f32 npyv_maxp_f32(npyv_f32 a, npyv_f32 b)
{
__mmask16 nn = _mm512_cmp_ps_mask(b, b, _CMP_ORD_Q);
@@ -84,7 +84,7 @@ NPY_FINLINE npyv_f64 npyv_maxp_f64(npyv_f64 a, npyv_f64 b)
#define npyv_min_f64 _mm512_min_pd
// Minimum, supports IEEE floating-point arithmetic (IEC 60559),
// - If one of the two vectors contains NaN, the equivalent element of the other vector is set
-// - Only if both corresponded elements are NaN, NaN is set.
+// - Only if both corresponded elements are NaN, NaN is set.
NPY_FINLINE npyv_f32 npyv_minp_f32(npyv_f32 a, npyv_f32 b)
{
__mmask16 nn = _mm512_cmp_ps_mask(b, b, _CMP_ORD_Q);
@@ -112,6 +112,10 @@ NPY_FINLINE npyv_f64 npyv_minp_f64(npyv_f64 a, npyv_f64 b)
#define npyv_min_u64 _mm512_min_epu64
#define npyv_min_s64 _mm512_min_epi64
+// round to nearest integer even
+#define npyv_rint_f32(A) _mm512_roundscale_ps(A, _MM_FROUND_TO_NEAREST_INT)
+#define npyv_rint_f64(A) _mm512_roundscale_pd(A, _MM_FROUND_TO_NEAREST_INT)
+
// ceil
#define npyv_ceil_f32(A) _mm512_roundscale_ps(A, _MM_FROUND_TO_POS_INF)
#define npyv_ceil_f64(A) _mm512_roundscale_pd(A, _MM_FROUND_TO_POS_INF)
@@ -120,4 +124,8 @@ NPY_FINLINE npyv_f64 npyv_minp_f64(npyv_f64 a, npyv_f64 b)
#define npyv_trunc_f32(A) _mm512_roundscale_ps(A, _MM_FROUND_TO_ZERO)
#define npyv_trunc_f64(A) _mm512_roundscale_pd(A, _MM_FROUND_TO_ZERO)
+// floor
+#define npyv_floor_f32(A) _mm512_roundscale_ps(A, _MM_FROUND_TO_NEG_INF)
+#define npyv_floor_f64(A) _mm512_roundscale_pd(A, _MM_FROUND_TO_NEG_INF)
+
#endif // _NPY_SIMD_AVX512_MATH_H
diff --git a/numpy/core/src/common/simd/intdiv.h b/numpy/core/src/common/simd/intdiv.h
index a7a461721..42f022c55 100644
--- a/numpy/core/src/common/simd/intdiv.h
+++ b/numpy/core/src/common/simd/intdiv.h
@@ -136,7 +136,7 @@ NPY_FINLINE npy_uint64 npyv__divh128_u64(npy_uint64 high, npy_uint64 divisor)
{
assert(divisor > 1);
npy_uint64 quotient;
-#if defined(_M_X64) && defined(_MSC_VER) && _MSC_VER >= 1920
+#if defined(_M_X64) && defined(_MSC_VER) && _MSC_VER >= 1920 && !defined(__clang__)
npy_uint64 remainder;
quotient = _udiv128(high, 0, divisor, &remainder);
(void)remainder;
diff --git a/numpy/core/src/common/simd/neon/math.h b/numpy/core/src/common/simd/neon/math.h
index 19e5cd846..4607d6f27 100644
--- a/numpy/core/src/common/simd/neon/math.h
+++ b/numpy/core/src/common/simd/neon/math.h
@@ -153,6 +153,33 @@ NPY_FINLINE npyv_s64 npyv_min_s64(npyv_s64 a, npyv_s64 b)
return vbslq_s64(npyv_cmplt_s64(a, b), a, b);
}
+// round to nearest integer even
+NPY_FINLINE npyv_f32 npyv_rint_f32(npyv_f32 a)
+{
+#ifdef NPY_HAVE_ASIMD
+ return vrndnq_f32(a);
+#else
+ // ARMv7 NEON only supports fp to int truncate conversion.
+ // a magic trick of adding 1.5 * 2**23 is used for rounding
+ // to nearest even and then substract this magic number to get
+ // the integer.
+ const npyv_s32 szero = vreinterpretq_s32_f32(vdupq_n_f32(-0.0f));
+ const npyv_f32 magic = vdupq_n_f32(12582912.0f); // 1.5 * 2**23
+ npyv_f32 round = vsubq_f32(vaddq_f32(a, magic), magic);
+ npyv_b32 overflow = vcleq_f32(vabsq_f32(a), vreinterpretq_f32_u32(vdupq_n_u32(0x4b000000)));
+ round = vbslq_f32(overflow, round, a);
+ // signed zero
+ round = vreinterpretq_f32_s32(vorrq_s32(
+ vreinterpretq_s32_f32(round),
+ vandq_s32(vreinterpretq_s32_f32(a), szero)
+ ));
+ return round;
+#endif
+}
+#if NPY_SIMD_F64
+ #define npyv_rint_f64 vrndnq_f64
+#endif // NPY_SIMD_F64
+
// ceil
#ifdef NPY_HAVE_ASIMD
#define npyv_ceil_f32 vrndpq_f32
@@ -223,4 +250,36 @@ NPY_FINLINE npyv_s64 npyv_min_s64(npyv_s64 a, npyv_s64 b)
#define npyv_trunc_f64 vrndq_f64
#endif // NPY_SIMD_F64
+// floor
+#ifdef NPY_HAVE_ASIMD
+ #define npyv_floor_f32 vrndmq_f32
+#else
+ NPY_FINLINE npyv_f32 npyv_floor_f32(npyv_f32 a)
+ {
+ const npyv_s32 szero = vreinterpretq_s32_f32(vdupq_n_f32(-0.0f));
+ const npyv_u32 one = vreinterpretq_u32_f32(vdupq_n_f32(1.0f));
+ const npyv_s32 max_int = vdupq_n_s32(0x7fffffff);
+
+ npyv_s32 roundi = vcvtq_s32_f32(a);
+ npyv_f32 round = vcvtq_f32_s32(roundi);
+ npyv_f32 floor = vsubq_f32(round, vreinterpretq_f32_u32(
+ vandq_u32(vcgtq_f32(round, a), one)
+ ));
+ // respect signed zero
+ npyv_f32 rzero = vreinterpretq_f32_s32(vorrq_s32(
+ vreinterpretq_s32_f32(floor),
+ vandq_s32(vreinterpretq_s32_f32(a), szero)
+ ));
+ npyv_u32 nnan = npyv_notnan_f32(a);
+ npyv_u32 overflow = vorrq_u32(
+ vceqq_s32(roundi, szero), vceqq_s32(roundi, max_int)
+ );
+
+ return vbslq_f32(vbicq_u32(nnan, overflow), rzero, a);
+ }
+#endif // NPY_HAVE_ASIMD
+#if NPY_SIMD_F64
+ #define npyv_floor_f64 vrndmq_f64
+#endif // NPY_SIMD_F64
+
#endif // _NPY_SIMD_NEON_MATH_H
diff --git a/numpy/core/src/common/simd/sse/math.h b/numpy/core/src/common/simd/sse/math.h
index 5daf7711e..e4b77b671 100644
--- a/numpy/core/src/common/simd/sse/math.h
+++ b/numpy/core/src/common/simd/sse/math.h
@@ -42,7 +42,7 @@ NPY_FINLINE npyv_f64 npyv_square_f64(npyv_f64 a)
#define npyv_max_f64 _mm_max_pd
// Maximum, supports IEEE floating-point arithmetic (IEC 60559),
// - If one of the two vectors contains NaN, the equivalent element of the other vector is set
-// - Only if both corresponded elements are NaN, NaN is set.
+// - Only if both corresponded elements are NaN, NaN is set.
NPY_FINLINE npyv_f32 npyv_maxp_f32(npyv_f32 a, npyv_f32 b)
{
__m128 nn = _mm_cmpord_ps(b, b);
@@ -95,7 +95,7 @@ NPY_FINLINE npyv_s64 npyv_max_s64(npyv_s64 a, npyv_s64 b)
#define npyv_min_f64 _mm_min_pd
// Minimum, supports IEEE floating-point arithmetic (IEC 60559),
// - If one of the two vectors contains NaN, the equivalent element of the other vector is set
-// - Only if both corresponded elements are NaN, NaN is set.
+// - Only if both corresponded elements are NaN, NaN is set.
NPY_FINLINE npyv_f32 npyv_minp_f32(npyv_f32 a, npyv_f32 b)
{
__m128 nn = _mm_cmpord_ps(b, b);
@@ -143,6 +143,38 @@ NPY_FINLINE npyv_s64 npyv_min_s64(npyv_s64 a, npyv_s64 b)
return npyv_select_s64(npyv_cmplt_s64(a, b), a, b);
}
+// round to nearest integer even
+NPY_FINLINE npyv_f32 npyv_rint_f32(npyv_f32 a)
+{
+#ifdef NPY_HAVE_SSE41
+ return _mm_round_ps(a, _MM_FROUND_TO_NEAREST_INT);
+#else
+ const npyv_f32 szero = _mm_set1_ps(-0.0f);
+ __m128i roundi = _mm_cvtps_epi32(a);
+ __m128i overflow = _mm_cmpeq_epi32(roundi, _mm_castps_si128(szero));
+ __m128 r = _mm_cvtepi32_ps(roundi);
+ // respect sign of zero
+ r = _mm_or_ps(r, _mm_and_ps(a, szero));
+ return npyv_select_f32(overflow, a, r);
+#endif
+}
+
+// round to nearest integer even
+NPY_FINLINE npyv_f64 npyv_rint_f64(npyv_f64 a)
+{
+#ifdef NPY_HAVE_SSE41
+ return _mm_round_pd(a, _MM_FROUND_TO_NEAREST_INT);
+#else
+ const npyv_f64 szero = _mm_set1_pd(-0.0);
+ const npyv_f64 two_power_52 = _mm_set1_pd(0x10000000000000);
+ npyv_f64 sign_two52 = _mm_or_pd(two_power_52, _mm_and_pd(a, szero));
+ // round by add magic number 2^52
+ npyv_f64 round = _mm_sub_pd(_mm_add_pd(a, sign_two52), sign_two52);
+ // respect signed zero, e.g. -0.5 -> -0.0
+ return _mm_or_pd(round, _mm_and_pd(a, szero));
+#endif
+}
+
// ceil
#ifdef NPY_HAVE_SSE41
#define npyv_ceil_f32 _mm_ceil_ps
@@ -202,4 +234,23 @@ NPY_FINLINE npyv_s64 npyv_min_s64(npyv_s64 a, npyv_s64 b)
}
#endif
+// floor
+#ifdef NPY_HAVE_SSE41
+ #define npyv_floor_f32 _mm_floor_ps
+ #define npyv_floor_f64 _mm_floor_pd
+#else
+ NPY_FINLINE npyv_f32 npyv_floor_f32(npyv_f32 a)
+ {
+ const npyv_f32 one = _mm_set1_ps(1.0f);
+ npyv_f32 round = npyv_rint_f32(a);
+ return _mm_sub_ps(round, _mm_and_ps(_mm_cmpgt_ps(round, a), one));
+ }
+ NPY_FINLINE npyv_f64 npyv_floor_f64(npyv_f64 a)
+ {
+ const npyv_f64 one = _mm_set1_pd(1.0);
+ npyv_f64 round = npyv_rint_f64(a);
+ return _mm_sub_pd(round, _mm_and_pd(_mm_cmpgt_pd(round, a), one));
+ }
+#endif // NPY_HAVE_SSE41
+
#endif // _NPY_SIMD_SSE_MATH_H
diff --git a/numpy/core/src/common/simd/vsx/math.h b/numpy/core/src/common/simd/vsx/math.h
index d138cae8a..444bc9e54 100644
--- a/numpy/core/src/common/simd/vsx/math.h
+++ b/numpy/core/src/common/simd/vsx/math.h
@@ -38,7 +38,7 @@ NPY_FINLINE npyv_f64 npyv_square_f64(npyv_f64 a)
#define npyv_max_f64 vec_max
// Maximum, supports IEEE floating-point arithmetic (IEC 60559),
// - If one of the two vectors contains NaN, the equivalent element of the other vector is set
-// - Only if both corresponded elements are NaN, NaN is set.
+// - Only if both corresponded elements are NaN, NaN is set.
#define npyv_maxp_f32 vec_max
#define npyv_maxp_f64 vec_max
// Maximum, integer operations
@@ -56,7 +56,7 @@ NPY_FINLINE npyv_f64 npyv_square_f64(npyv_f64 a)
#define npyv_min_f64 vec_min
// Minimum, supports IEEE floating-point arithmetic (IEC 60559),
// - If one of the two vectors contains NaN, the equivalent element of the other vector is set
-// - Only if both corresponded elements are NaN, NaN is set.
+// - Only if both corresponded elements are NaN, NaN is set.
#define npyv_minp_f32 vec_min
#define npyv_minp_f64 vec_min
// Minimum, integer operations
@@ -69,6 +69,10 @@ NPY_FINLINE npyv_f64 npyv_square_f64(npyv_f64 a)
#define npyv_min_u64 vec_min
#define npyv_min_s64 vec_min
+// round to nearest int even
+#define npyv_rint_f32 vec_rint
+#define npyv_rint_f64 vec_rint
+
// ceil
#define npyv_ceil_f32 vec_ceil
#define npyv_ceil_f64 vec_ceil
@@ -77,4 +81,8 @@ NPY_FINLINE npyv_f64 npyv_square_f64(npyv_f64 a)
#define npyv_trunc_f32 vec_trunc
#define npyv_trunc_f64 vec_trunc
+// floor
+#define npyv_floor_f32 vec_floor
+#define npyv_floor_f64 vec_floor
+
#endif // _NPY_SIMD_VSX_MATH_H
diff --git a/numpy/core/src/multiarray/arraytypes.c.src b/numpy/core/src/multiarray/arraytypes.c.src
index 71808cc48..71401c60e 100644
--- a/numpy/core/src/multiarray/arraytypes.c.src
+++ b/numpy/core/src/multiarray/arraytypes.c.src
@@ -2849,7 +2849,7 @@ static int
#define LT(a,b) ((a) < (b) || ((b) != (b) && (a) ==(a)))
static int
-@TYPE@_compare(@type@ *pa, @type@ *pb)
+@TYPE@_compare(@type@ *pa, @type@ *pb, PyArrayObject *NPY_UNUSED(ap))
{
const @type@ a = *pa;
const @type@ b = *pb;
@@ -2869,7 +2869,7 @@ static int
static int
-C@TYPE@_compare(@type@ *pa, @type@ *pb)
+C@TYPE@_compare(@type@ *pa, @type@ *pb, PyArrayObject *NPY_UNUSED(ap))
{
const @type@ ar = pa[0];
const @type@ ai = pa[1];
@@ -2924,7 +2924,7 @@ C@TYPE@_compare(@type@ *pa, @type@ *pb)
*/
static int
-@TYPE@_compare(@type@ *pa, @type@ *pb)
+@TYPE@_compare(@type@ *pa, @type@ *pb, PyArrayObject *NPY_UNUSED(ap))
{
const @type@ a = *pa;
const @type@ b = *pb;
diff --git a/numpy/core/src/multiarray/common_dtype.c b/numpy/core/src/multiarray/common_dtype.c
index ca80b1ed7..3561a905a 100644
--- a/numpy/core/src/multiarray/common_dtype.c
+++ b/numpy/core/src/multiarray/common_dtype.c
@@ -41,7 +41,7 @@
* @param dtype2 Second DType class.
* @return The common DType or NULL with an error set
*/
-NPY_NO_EXPORT NPY_INLINE PyArray_DTypeMeta *
+NPY_NO_EXPORT PyArray_DTypeMeta *
PyArray_CommonDType(PyArray_DTypeMeta *dtype1, PyArray_DTypeMeta *dtype2)
{
if (dtype1 == dtype2) {
diff --git a/numpy/core/src/npysort/heapsort.c.src b/numpy/core/src/npysort/heapsort.c.src
deleted file mode 100644
index 4bfea1388..000000000
--- a/numpy/core/src/npysort/heapsort.c.src
+++ /dev/null
@@ -1,402 +0,0 @@
-/* -*- c -*- */
-
-/*
- * The purpose of this module is to add faster sort functions
- * that are type-specific. This is done by altering the
- * function table for the builtin descriptors.
- *
- * These sorting functions are copied almost directly from numarray
- * with a few modifications (complex comparisons compare the imaginary
- * part if the real parts are equal, for example), and the names
- * are changed.
- *
- * The original sorting code is due to Charles R. Harris who wrote
- * it for numarray.
- */
-
-/*
- * Quick sort is usually the fastest, but the worst case scenario can
- * be slower than the merge and heap sorts. The merge sort requires
- * extra memory and so for large arrays may not be useful.
- *
- * The merge sort is *stable*, meaning that equal components
- * are unmoved from their entry versions, so it can be used to
- * implement lexigraphic sorting on multiple keys.
- *
- * The heap sort is included for completeness.
- */
-
-#define NPY_NO_DEPRECATED_API NPY_API_VERSION
-
-#include "npy_sort.h"
-#include "npysort_common.h"
-#include <stdlib.h>
-
-#define NOT_USED NPY_UNUSED(unused)
-#define PYA_QS_STACK 100
-#define SMALL_QUICKSORT 15
-#define SMALL_MERGESORT 20
-#define SMALL_STRING 16
-
-
-/*
- *****************************************************************************
- ** NUMERIC SORTS **
- *****************************************************************************
- */
-
-
-/**begin repeat
- *
- * #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG,
- * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE,
- * CFLOAT, CDOUBLE, CLONGDOUBLE, DATETIME, TIMEDELTA#
- * #suff = bool, byte, ubyte, short, ushort, int, uint, long, ulong,
- * longlong, ulonglong, half, float, double, longdouble,
- * cfloat, cdouble, clongdouble, datetime, timedelta#
- * #type = npy_bool, npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int,
- * npy_uint, npy_long, npy_ulong, npy_longlong, npy_ulonglong,
- * npy_ushort, npy_float, npy_double, npy_longdouble, npy_cfloat,
- * npy_cdouble, npy_clongdouble, npy_datetime, npy_timedelta#
- */
-
-NPY_NO_EXPORT int
-heapsort_@suff@(void *start, npy_intp n, void *NOT_USED)
-{
- @type@ tmp, *a;
- npy_intp i,j,l;
-
- /* The array needs to be offset by one for heapsort indexing */
- a = (@type@ *)start - 1;
-
- for (l = n>>1; l > 0; --l) {
- tmp = a[l];
- for (i = l, j = l<<1; j <= n;) {
- if (j < n && @TYPE@_LT(a[j], a[j+1])) {
- j += 1;
- }
- if (@TYPE@_LT(tmp, a[j])) {
- a[i] = a[j];
- i = j;
- j += j;
- }
- else {
- break;
- }
- }
- a[i] = tmp;
- }
-
- for (; n > 1;) {
- tmp = a[n];
- a[n] = a[1];
- n -= 1;
- for (i = 1, j = 2; j <= n;) {
- if (j < n && @TYPE@_LT(a[j], a[j+1])) {
- j++;
- }
- if (@TYPE@_LT(tmp, a[j])) {
- a[i] = a[j];
- i = j;
- j += j;
- }
- else {
- break;
- }
- }
- a[i] = tmp;
- }
-
- return 0;
-}
-
-
-NPY_NO_EXPORT int
-aheapsort_@suff@(void *vv, npy_intp *tosort, npy_intp n, void *NOT_USED)
-{
- @type@ *v = vv;
- npy_intp *a, i,j,l, tmp;
- /* The arrays need to be offset by one for heapsort indexing */
- a = tosort - 1;
-
- for (l = n>>1; l > 0; --l) {
- tmp = a[l];
- for (i = l, j = l<<1; j <= n;) {
- if (j < n && @TYPE@_LT(v[a[j]], v[a[j+1]])) {
- j += 1;
- }
- if (@TYPE@_LT(v[tmp], v[a[j]])) {
- a[i] = a[j];
- i = j;
- j += j;
- }
- else {
- break;
- }
- }
- a[i] = tmp;
- }
-
- for (; n > 1;) {
- tmp = a[n];
- a[n] = a[1];
- n -= 1;
- for (i = 1, j = 2; j <= n;) {
- if (j < n && @TYPE@_LT(v[a[j]], v[a[j+1]])) {
- j++;
- }
- if (@TYPE@_LT(v[tmp], v[a[j]])) {
- a[i] = a[j];
- i = j;
- j += j;
- }
- else {
- break;
- }
- }
- a[i] = tmp;
- }
-
- return 0;
-}
-
-/**end repeat**/
-
-
-/*
- *****************************************************************************
- ** STRING SORTS **
- *****************************************************************************
- */
-
-
-/**begin repeat
- *
- * #TYPE = STRING, UNICODE#
- * #suff = string, unicode#
- * #type = npy_char, npy_ucs4#
- */
-
-NPY_NO_EXPORT int
-heapsort_@suff@(void *start, npy_intp n, void *varr)
-{
- PyArrayObject *arr = varr;
- size_t len = PyArray_ITEMSIZE(arr)/sizeof(@type@);
- @type@ *tmp = malloc(PyArray_ITEMSIZE(arr));
- @type@ *a = (@type@ *)start - len;
- npy_intp i, j, l;
-
- if (tmp == NULL) {
- return -NPY_ENOMEM;
- }
-
- for (l = n>>1; l > 0; --l) {
- @TYPE@_COPY(tmp, a + l*len, len);
- for (i = l, j = l<<1; j <= n;) {
- if (j < n && @TYPE@_LT(a + j*len, a + (j+1)*len, len))
- j += 1;
- if (@TYPE@_LT(tmp, a + j*len, len)) {
- @TYPE@_COPY(a + i*len, a + j*len, len);
- i = j;
- j += j;
- }
- else {
- break;
- }
- }
- @TYPE@_COPY(a + i*len, tmp, len);
- }
-
- for (; n > 1;) {
- @TYPE@_COPY(tmp, a + n*len, len);
- @TYPE@_COPY(a + n*len, a + len, len);
- n -= 1;
- for (i = 1, j = 2; j <= n;) {
- if (j < n && @TYPE@_LT(a + j*len, a + (j+1)*len, len))
- j++;
- if (@TYPE@_LT(tmp, a + j*len, len)) {
- @TYPE@_COPY(a + i*len, a + j*len, len);
- i = j;
- j += j;
- }
- else {
- break;
- }
- }
- @TYPE@_COPY(a + i*len, tmp, len);
- }
-
- free(tmp);
- return 0;
-}
-
-
-NPY_NO_EXPORT int
-aheapsort_@suff@(void *vv, npy_intp *tosort, npy_intp n, void *varr)
-{
- @type@ *v = vv;
- PyArrayObject *arr = varr;
- size_t len = PyArray_ITEMSIZE(arr)/sizeof(@type@);
- npy_intp *a, i,j,l, tmp;
-
- /* The array needs to be offset by one for heapsort indexing */
- a = tosort - 1;
-
- for (l = n>>1; l > 0; --l) {
- tmp = a[l];
- for (i = l, j = l<<1; j <= n;) {
- if (j < n && @TYPE@_LT(v + a[j]*len, v + a[j+1]*len, len))
- j += 1;
- if (@TYPE@_LT(v + tmp*len, v + a[j]*len, len)) {
- a[i] = a[j];
- i = j;
- j += j;
- }
- else {
- break;
- }
- }
- a[i] = tmp;
- }
-
- for (; n > 1;) {
- tmp = a[n];
- a[n] = a[1];
- n -= 1;
- for (i = 1, j = 2; j <= n;) {
- if (j < n && @TYPE@_LT(v + a[j]*len, v + a[j+1]*len, len))
- j++;
- if (@TYPE@_LT(v + tmp*len, v + a[j]*len, len)) {
- a[i] = a[j];
- i = j;
- j += j;
- }
- else {
- break;
- }
- }
- a[i] = tmp;
- }
-
- return 0;
-}
-
-/**end repeat**/
-
-
-/*
- *****************************************************************************
- ** GENERIC SORT **
- *****************************************************************************
- */
-
-
-NPY_NO_EXPORT int
-npy_heapsort(void *start, npy_intp num, void *varr)
-{
- PyArrayObject *arr = varr;
- npy_intp elsize = PyArray_ITEMSIZE(arr);
- PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare;
- char *tmp = malloc(elsize);
- char *a = (char *)start - elsize;
- npy_intp i, j, l;
-
- if (tmp == NULL) {
- return -NPY_ENOMEM;
- }
-
- for (l = num >> 1; l > 0; --l) {
- GENERIC_COPY(tmp, a + l*elsize, elsize);
- for (i = l, j = l << 1; j <= num;) {
- if (j < num && cmp(a + j*elsize, a + (j+1)*elsize, arr) < 0) {
- ++j;
- }
- if (cmp(tmp, a + j*elsize, arr) < 0) {
- GENERIC_COPY(a + i*elsize, a + j*elsize, elsize);
- i = j;
- j += j;
- }
- else {
- break;
- }
- }
- GENERIC_COPY(a + i*elsize, tmp, elsize);
- }
-
- for (; num > 1;) {
- GENERIC_COPY(tmp, a + num*elsize, elsize);
- GENERIC_COPY(a + num*elsize, a + elsize, elsize);
- num -= 1;
- for (i = 1, j = 2; j <= num;) {
- if (j < num && cmp(a + j*elsize, a + (j+1)*elsize, arr) < 0) {
- ++j;
- }
- if (cmp(tmp, a + j*elsize, arr) < 0) {
- GENERIC_COPY(a + i*elsize, a + j*elsize, elsize);
- i = j;
- j += j;
- }
- else {
- break;
- }
- }
- GENERIC_COPY(a + i*elsize, tmp, elsize);
- }
-
- free(tmp);
- return 0;
-}
-
-
-NPY_NO_EXPORT int
-npy_aheapsort(void *vv, npy_intp *tosort, npy_intp n, void *varr)
-{
- char *v = vv;
- PyArrayObject *arr = varr;
- npy_intp elsize = PyArray_ITEMSIZE(arr);
- PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare;
- npy_intp *a, i, j, l, tmp;
-
- /* The array needs to be offset by one for heapsort indexing */
- a = tosort - 1;
-
- for (l = n >> 1; l > 0; --l) {
- tmp = a[l];
- for (i = l, j = l<<1; j <= n;) {
- if (j < n && cmp(v + a[j]*elsize, v + a[j+1]*elsize, arr) < 0) {
- ++j;
- }
- if (cmp(v + tmp*elsize, v + a[j]*elsize, arr) < 0) {
- a[i] = a[j];
- i = j;
- j += j;
- }
- else {
- break;
- }
- }
- a[i] = tmp;
- }
-
- for (; n > 1;) {
- tmp = a[n];
- a[n] = a[1];
- n -= 1;
- for (i = 1, j = 2; j <= n;) {
- if (j < n && cmp(v + a[j]*elsize, v + a[j+1]*elsize, arr) < 0) {
- ++j;
- }
- if (cmp(v + tmp*elsize, v + a[j]*elsize, arr) < 0) {
- a[i] = a[j];
- i = j;
- j += j;
- }
- else {
- break;
- }
- }
- a[i] = tmp;
- }
-
- return 0;
-}
diff --git a/numpy/core/src/npysort/heapsort.cpp b/numpy/core/src/npysort/heapsort.cpp
new file mode 100644
index 000000000..3893bf5c2
--- /dev/null
+++ b/numpy/core/src/npysort/heapsort.cpp
@@ -0,0 +1,619 @@
+/* -*- c -*- */
+
+/*
+ * The purpose of this module is to add faster sort functions
+ * that are type-specific. This is done by altering the
+ * function table for the builtin descriptors.
+ *
+ * These sorting functions are copied almost directly from numarray
+ * with a few modifications (complex comparisons compare the imaginary
+ * part if the real parts are equal, for example), and the names
+ * are changed.
+ *
+ * The original sorting code is due to Charles R. Harris who wrote
+ * it for numarray.
+ */
+
+/*
+ * Quick sort is usually the fastest, but the worst case scenario can
+ * be slower than the merge and heap sorts. The merge sort requires
+ * extra memory and so for large arrays may not be useful.
+ *
+ * The merge sort is *stable*, meaning that equal components
+ * are unmoved from their entry versions, so it can be used to
+ * implement lexigraphic sorting on multiple keys.
+ *
+ * The heap sort is included for completeness.
+ */
+
+#define NPY_NO_DEPRECATED_API NPY_API_VERSION
+
+#include "npy_sort.h"
+#include "npysort_common.h"
+#include "numpy_tag.h"
+
+#include <cstdlib>
+
+#define NOT_USED NPY_UNUSED(unused)
+#define PYA_QS_STACK 100
+#define SMALL_QUICKSORT 15
+#define SMALL_MERGESORT 20
+#define SMALL_STRING 16
+
+/*
+ *****************************************************************************
+ ** NUMERIC SORTS **
+ *****************************************************************************
+ */
+
+template <typename Tag, typename type>
+static int
+heapsort_(type *start, npy_intp n)
+{
+ type tmp, *a;
+ npy_intp i, j, l;
+
+ /* The array needs to be offset by one for heapsort indexing */
+ a = start - 1;
+
+ for (l = n >> 1; l > 0; --l) {
+ tmp = a[l];
+ for (i = l, j = l << 1; j <= n;) {
+ if (j < n && Tag::less(a[j], a[j + 1])) {
+ j += 1;
+ }
+ if (Tag::less(tmp, a[j])) {
+ a[i] = a[j];
+ i = j;
+ j += j;
+ }
+ else {
+ break;
+ }
+ }
+ a[i] = tmp;
+ }
+
+ for (; n > 1;) {
+ tmp = a[n];
+ a[n] = a[1];
+ n -= 1;
+ for (i = 1, j = 2; j <= n;) {
+ if (j < n && Tag::less(a[j], a[j + 1])) {
+ j++;
+ }
+ if (Tag::less(tmp, a[j])) {
+ a[i] = a[j];
+ i = j;
+ j += j;
+ }
+ else {
+ break;
+ }
+ }
+ a[i] = tmp;
+ }
+
+ return 0;
+}
+
+template <typename Tag, typename type>
+static int
+aheapsort_(type *vv, npy_intp *tosort, npy_intp n)
+{
+ type *v = vv;
+ npy_intp *a, i, j, l, tmp;
+ /* The arrays need to be offset by one for heapsort indexing */
+ a = tosort - 1;
+
+ for (l = n >> 1; l > 0; --l) {
+ tmp = a[l];
+ for (i = l, j = l << 1; j <= n;) {
+ if (j < n && Tag::less(v[a[j]], v[a[j + 1]])) {
+ j += 1;
+ }
+ if (Tag::less(v[tmp], v[a[j]])) {
+ a[i] = a[j];
+ i = j;
+ j += j;
+ }
+ else {
+ break;
+ }
+ }
+ a[i] = tmp;
+ }
+
+ for (; n > 1;) {
+ tmp = a[n];
+ a[n] = a[1];
+ n -= 1;
+ for (i = 1, j = 2; j <= n;) {
+ if (j < n && Tag::less(v[a[j]], v[a[j + 1]])) {
+ j++;
+ }
+ if (Tag::less(v[tmp], v[a[j]])) {
+ a[i] = a[j];
+ i = j;
+ j += j;
+ }
+ else {
+ break;
+ }
+ }
+ a[i] = tmp;
+ }
+
+ return 0;
+}
+
+/*
+ *****************************************************************************
+ ** STRING SORTS **
+ *****************************************************************************
+ */
+
+template <typename Tag, typename type>
+NPY_NO_EXPORT int
+string_heapsort_(type *start, npy_intp n, void *varr)
+{
+ PyArrayObject *arr = (PyArrayObject *)varr;
+ size_t len = PyArray_ITEMSIZE(arr) / sizeof(type);
+ type *tmp = (type *)malloc(PyArray_ITEMSIZE(arr));
+ type *a = (type *)start - len;
+ npy_intp i, j, l;
+
+ if (tmp == NULL) {
+ return -NPY_ENOMEM;
+ }
+
+ for (l = n >> 1; l > 0; --l) {
+ Tag::copy(tmp, a + l * len, len);
+ for (i = l, j = l << 1; j <= n;) {
+ if (j < n && Tag::less(a + j * len, a + (j + 1) * len, len))
+ j += 1;
+ if (Tag::less(tmp, a + j * len, len)) {
+ Tag::copy(a + i * len, a + j * len, len);
+ i = j;
+ j += j;
+ }
+ else {
+ break;
+ }
+ }
+ Tag::copy(a + i * len, tmp, len);
+ }
+
+ for (; n > 1;) {
+ Tag::copy(tmp, a + n * len, len);
+ Tag::copy(a + n * len, a + len, len);
+ n -= 1;
+ for (i = 1, j = 2; j <= n;) {
+ if (j < n && Tag::less(a + j * len, a + (j + 1) * len, len))
+ j++;
+ if (Tag::less(tmp, a + j * len, len)) {
+ Tag::copy(a + i * len, a + j * len, len);
+ i = j;
+ j += j;
+ }
+ else {
+ break;
+ }
+ }
+ Tag::copy(a + i * len, tmp, len);
+ }
+
+ free(tmp);
+ return 0;
+}
+
+template <typename Tag, typename type>
+NPY_NO_EXPORT int
+string_aheapsort_(type *vv, npy_intp *tosort, npy_intp n, void *varr)
+{
+ type *v = vv;
+ PyArrayObject *arr = (PyArrayObject *)varr;
+ size_t len = PyArray_ITEMSIZE(arr) / sizeof(type);
+ npy_intp *a, i, j, l, tmp;
+
+ /* The array needs to be offset by one for heapsort indexing */
+ a = tosort - 1;
+
+ for (l = n >> 1; l > 0; --l) {
+ tmp = a[l];
+ for (i = l, j = l << 1; j <= n;) {
+ if (j < n && Tag::less(v + a[j] * len, v + a[j + 1] * len, len))
+ j += 1;
+ if (Tag::less(v + tmp * len, v + a[j] * len, len)) {
+ a[i] = a[j];
+ i = j;
+ j += j;
+ }
+ else {
+ break;
+ }
+ }
+ a[i] = tmp;
+ }
+
+ for (; n > 1;) {
+ tmp = a[n];
+ a[n] = a[1];
+ n -= 1;
+ for (i = 1, j = 2; j <= n;) {
+ if (j < n && Tag::less(v + a[j] * len, v + a[j + 1] * len, len))
+ j++;
+ if (Tag::less(v + tmp * len, v + a[j] * len, len)) {
+ a[i] = a[j];
+ i = j;
+ j += j;
+ }
+ else {
+ break;
+ }
+ }
+ a[i] = tmp;
+ }
+
+ return 0;
+}
+
+/**end repeat**/
+
+/*
+ *****************************************************************************
+ ** GENERIC SORT **
+ *****************************************************************************
+ */
+
+NPY_NO_EXPORT int
+npy_heapsort(void *start, npy_intp num, void *varr)
+{
+ PyArrayObject *arr = (PyArrayObject *)varr;
+ npy_intp elsize = PyArray_ITEMSIZE(arr);
+ PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare;
+ char *tmp = (char *)malloc(elsize);
+ char *a = (char *)start - elsize;
+ npy_intp i, j, l;
+
+ if (tmp == NULL) {
+ return -NPY_ENOMEM;
+ }
+
+ for (l = num >> 1; l > 0; --l) {
+ GENERIC_COPY(tmp, a + l * elsize, elsize);
+ for (i = l, j = l << 1; j <= num;) {
+ if (j < num &&
+ cmp(a + j * elsize, a + (j + 1) * elsize, arr) < 0) {
+ ++j;
+ }
+ if (cmp(tmp, a + j * elsize, arr) < 0) {
+ GENERIC_COPY(a + i * elsize, a + j * elsize, elsize);
+ i = j;
+ j += j;
+ }
+ else {
+ break;
+ }
+ }
+ GENERIC_COPY(a + i * elsize, tmp, elsize);
+ }
+
+ for (; num > 1;) {
+ GENERIC_COPY(tmp, a + num * elsize, elsize);
+ GENERIC_COPY(a + num * elsize, a + elsize, elsize);
+ num -= 1;
+ for (i = 1, j = 2; j <= num;) {
+ if (j < num &&
+ cmp(a + j * elsize, a + (j + 1) * elsize, arr) < 0) {
+ ++j;
+ }
+ if (cmp(tmp, a + j * elsize, arr) < 0) {
+ GENERIC_COPY(a + i * elsize, a + j * elsize, elsize);
+ i = j;
+ j += j;
+ }
+ else {
+ break;
+ }
+ }
+ GENERIC_COPY(a + i * elsize, tmp, elsize);
+ }
+
+ free(tmp);
+ return 0;
+}
+
+NPY_NO_EXPORT int
+npy_aheapsort(void *vv, npy_intp *tosort, npy_intp n, void *varr)
+{
+ char *v = (char *)vv;
+ PyArrayObject *arr = (PyArrayObject *)varr;
+ npy_intp elsize = PyArray_ITEMSIZE(arr);
+ PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare;
+ npy_intp *a, i, j, l, tmp;
+
+ /* The array needs to be offset by one for heapsort indexing */
+ a = tosort - 1;
+
+ for (l = n >> 1; l > 0; --l) {
+ tmp = a[l];
+ for (i = l, j = l << 1; j <= n;) {
+ if (j < n &&
+ cmp(v + a[j] * elsize, v + a[j + 1] * elsize, arr) < 0) {
+ ++j;
+ }
+ if (cmp(v + tmp * elsize, v + a[j] * elsize, arr) < 0) {
+ a[i] = a[j];
+ i = j;
+ j += j;
+ }
+ else {
+ break;
+ }
+ }
+ a[i] = tmp;
+ }
+
+ for (; n > 1;) {
+ tmp = a[n];
+ a[n] = a[1];
+ n -= 1;
+ for (i = 1, j = 2; j <= n;) {
+ if (j < n &&
+ cmp(v + a[j] * elsize, v + a[j + 1] * elsize, arr) < 0) {
+ ++j;
+ }
+ if (cmp(v + tmp * elsize, v + a[j] * elsize, arr) < 0) {
+ a[i] = a[j];
+ i = j;
+ j += j;
+ }
+ else {
+ break;
+ }
+ }
+ a[i] = tmp;
+ }
+
+ return 0;
+}
+
+/***************************************
+ * C > C++ dispatch
+ ***************************************/
+
+NPY_NO_EXPORT int
+heapsort_bool(void *start, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return heapsort_<npy::bool_tag>((npy_bool *)start, n);
+}
+NPY_NO_EXPORT int
+heapsort_byte(void *start, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return heapsort_<npy::byte_tag>((npy_byte *)start, n);
+}
+NPY_NO_EXPORT int
+heapsort_ubyte(void *start, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return heapsort_<npy::ubyte_tag>((npy_ubyte *)start, n);
+}
+NPY_NO_EXPORT int
+heapsort_short(void *start, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return heapsort_<npy::short_tag>((npy_short *)start, n);
+}
+NPY_NO_EXPORT int
+heapsort_ushort(void *start, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return heapsort_<npy::ushort_tag>((npy_ushort *)start, n);
+}
+NPY_NO_EXPORT int
+heapsort_int(void *start, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return heapsort_<npy::int_tag>((npy_int *)start, n);
+}
+NPY_NO_EXPORT int
+heapsort_uint(void *start, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return heapsort_<npy::uint_tag>((npy_uint *)start, n);
+}
+NPY_NO_EXPORT int
+heapsort_long(void *start, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return heapsort_<npy::long_tag>((npy_long *)start, n);
+}
+NPY_NO_EXPORT int
+heapsort_ulong(void *start, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return heapsort_<npy::ulong_tag>((npy_ulong *)start, n);
+}
+NPY_NO_EXPORT int
+heapsort_longlong(void *start, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return heapsort_<npy::longlong_tag>((npy_longlong *)start, n);
+}
+NPY_NO_EXPORT int
+heapsort_ulonglong(void *start, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return heapsort_<npy::ulonglong_tag>((npy_ulonglong *)start, n);
+}
+NPY_NO_EXPORT int
+heapsort_half(void *start, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return heapsort_<npy::half_tag>((npy_half *)start, n);
+}
+NPY_NO_EXPORT int
+heapsort_float(void *start, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return heapsort_<npy::float_tag>((npy_float *)start, n);
+}
+NPY_NO_EXPORT int
+heapsort_double(void *start, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return heapsort_<npy::double_tag>((npy_double *)start, n);
+}
+NPY_NO_EXPORT int
+heapsort_longdouble(void *start, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return heapsort_<npy::longdouble_tag>((npy_longdouble *)start, n);
+}
+NPY_NO_EXPORT int
+heapsort_cfloat(void *start, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return heapsort_<npy::cfloat_tag>((npy_cfloat *)start, n);
+}
+NPY_NO_EXPORT int
+heapsort_cdouble(void *start, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return heapsort_<npy::cdouble_tag>((npy_cdouble *)start, n);
+}
+NPY_NO_EXPORT int
+heapsort_clongdouble(void *start, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return heapsort_<npy::clongdouble_tag>((npy_clongdouble *)start, n);
+}
+NPY_NO_EXPORT int
+heapsort_datetime(void *start, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return heapsort_<npy::datetime_tag>((npy_datetime *)start, n);
+}
+NPY_NO_EXPORT int
+heapsort_timedelta(void *start, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return heapsort_<npy::timedelta_tag>((npy_timedelta *)start, n);
+}
+
+NPY_NO_EXPORT int
+aheapsort_bool(void *vv, npy_intp *tosort, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return aheapsort_<npy::bool_tag>((npy_bool *)vv, tosort, n);
+}
+NPY_NO_EXPORT int
+aheapsort_byte(void *vv, npy_intp *tosort, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return aheapsort_<npy::byte_tag>((npy_byte *)vv, tosort, n);
+}
+NPY_NO_EXPORT int
+aheapsort_ubyte(void *vv, npy_intp *tosort, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return aheapsort_<npy::ubyte_tag>((npy_ubyte *)vv, tosort, n);
+}
+NPY_NO_EXPORT int
+aheapsort_short(void *vv, npy_intp *tosort, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return aheapsort_<npy::short_tag>((npy_short *)vv, tosort, n);
+}
+NPY_NO_EXPORT int
+aheapsort_ushort(void *vv, npy_intp *tosort, npy_intp n,
+ void *NPY_UNUSED(varr))
+{
+ return aheapsort_<npy::ushort_tag>((npy_ushort *)vv, tosort, n);
+}
+NPY_NO_EXPORT int
+aheapsort_int(void *vv, npy_intp *tosort, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return aheapsort_<npy::int_tag>((npy_int *)vv, tosort, n);
+}
+NPY_NO_EXPORT int
+aheapsort_uint(void *vv, npy_intp *tosort, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return aheapsort_<npy::uint_tag>((npy_uint *)vv, tosort, n);
+}
+NPY_NO_EXPORT int
+aheapsort_long(void *vv, npy_intp *tosort, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return aheapsort_<npy::long_tag>((npy_long *)vv, tosort, n);
+}
+NPY_NO_EXPORT int
+aheapsort_ulong(void *vv, npy_intp *tosort, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return aheapsort_<npy::ulong_tag>((npy_ulong *)vv, tosort, n);
+}
+NPY_NO_EXPORT int
+aheapsort_longlong(void *vv, npy_intp *tosort, npy_intp n,
+ void *NPY_UNUSED(varr))
+{
+ return aheapsort_<npy::longlong_tag>((npy_longlong *)vv, tosort, n);
+}
+NPY_NO_EXPORT int
+aheapsort_ulonglong(void *vv, npy_intp *tosort, npy_intp n,
+ void *NPY_UNUSED(varr))
+{
+ return aheapsort_<npy::ulonglong_tag>((npy_ulonglong *)vv, tosort, n);
+}
+NPY_NO_EXPORT int
+aheapsort_half(void *vv, npy_intp *tosort, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return aheapsort_<npy::half_tag>((npy_half *)vv, tosort, n);
+}
+NPY_NO_EXPORT int
+aheapsort_float(void *vv, npy_intp *tosort, npy_intp n, void *NPY_UNUSED(varr))
+{
+ return aheapsort_<npy::float_tag>((npy_float *)vv, tosort, n);
+}
+NPY_NO_EXPORT int
+aheapsort_double(void *vv, npy_intp *tosort, npy_intp n,
+ void *NPY_UNUSED(varr))
+{
+ return aheapsort_<npy::double_tag>((npy_double *)vv, tosort, n);
+}
+NPY_NO_EXPORT int
+aheapsort_longdouble(void *vv, npy_intp *tosort, npy_intp n,
+ void *NPY_UNUSED(varr))
+{
+ return aheapsort_<npy::longdouble_tag>((npy_longdouble *)vv, tosort, n);
+}
+NPY_NO_EXPORT int
+aheapsort_cfloat(void *vv, npy_intp *tosort, npy_intp n,
+ void *NPY_UNUSED(varr))
+{
+ return aheapsort_<npy::cfloat_tag>((npy_cfloat *)vv, tosort, n);
+}
+NPY_NO_EXPORT int
+aheapsort_cdouble(void *vv, npy_intp *tosort, npy_intp n,
+ void *NPY_UNUSED(varr))
+{
+ return aheapsort_<npy::cdouble_tag>((npy_cdouble *)vv, tosort, n);
+}
+NPY_NO_EXPORT int
+aheapsort_clongdouble(void *vv, npy_intp *tosort, npy_intp n,
+ void *NPY_UNUSED(varr))
+{
+ return aheapsort_<npy::clongdouble_tag>((npy_clongdouble *)vv, tosort, n);
+}
+NPY_NO_EXPORT int
+aheapsort_datetime(void *vv, npy_intp *tosort, npy_intp n,
+ void *NPY_UNUSED(varr))
+{
+ return aheapsort_<npy::datetime_tag>((npy_datetime *)vv, tosort, n);
+}
+NPY_NO_EXPORT int
+aheapsort_timedelta(void *vv, npy_intp *tosort, npy_intp n,
+ void *NPY_UNUSED(varr))
+{
+ return aheapsort_<npy::timedelta_tag>((npy_timedelta *)vv, tosort, n);
+}
+
+NPY_NO_EXPORT int
+heapsort_string(void *start, npy_intp n, void *varr)
+{
+ return string_heapsort_<npy::string_tag>((npy_char *)start, n, varr);
+}
+NPY_NO_EXPORT int
+heapsort_unicode(void *start, npy_intp n, void *varr)
+{
+ return string_heapsort_<npy::unicode_tag>((npy_ucs4 *)start, n, varr);
+}
+
+NPY_NO_EXPORT int
+aheapsort_string(void *vv, npy_intp *tosort, npy_intp n, void *varr)
+{
+ return string_aheapsort_<npy::string_tag>((npy_char *)vv, tosort, n, varr);
+}
+NPY_NO_EXPORT int
+aheapsort_unicode(void *vv, npy_intp *tosort, npy_intp n, void *varr)
+{
+ return string_aheapsort_<npy::unicode_tag>((npy_ucs4 *)vv, tosort, n,
+ varr);
+}
diff --git a/numpy/core/src/npysort/mergesort.c.src b/numpy/core/src/npysort/mergesort.c.src
deleted file mode 100644
index f83fbf758..000000000
--- a/numpy/core/src/npysort/mergesort.c.src
+++ /dev/null
@@ -1,511 +0,0 @@
-/* -*- c -*- */
-
-/*
- * The purpose of this module is to add faster sort functions
- * that are type-specific. This is done by altering the
- * function table for the builtin descriptors.
- *
- * These sorting functions are copied almost directly from numarray
- * with a few modifications (complex comparisons compare the imaginary
- * part if the real parts are equal, for example), and the names
- * are changed.
- *
- * The original sorting code is due to Charles R. Harris who wrote
- * it for numarray.
- */
-
-/*
- * Quick sort is usually the fastest, but the worst case scenario can
- * be slower than the merge and heap sorts. The merge sort requires
- * extra memory and so for large arrays may not be useful.
- *
- * The merge sort is *stable*, meaning that equal components
- * are unmoved from their entry versions, so it can be used to
- * implement lexigraphic sorting on multiple keys.
- *
- * The heap sort is included for completeness.
- */
-
-#define NPY_NO_DEPRECATED_API NPY_API_VERSION
-
-#include "npy_sort.h"
-#include "npysort_common.h"
-#include <stdlib.h>
-
-#define NOT_USED NPY_UNUSED(unused)
-#define PYA_QS_STACK 100
-#define SMALL_QUICKSORT 15
-#define SMALL_MERGESORT 20
-#define SMALL_STRING 16
-
-
-/*
- *****************************************************************************
- ** NUMERIC SORTS **
- *****************************************************************************
- */
-
-
-/**begin repeat
- *
- * #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG,
- * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE,
- * CFLOAT, CDOUBLE, CLONGDOUBLE, DATETIME, TIMEDELTA#
- * #suff = bool, byte, ubyte, short, ushort, int, uint, long, ulong,
- * longlong, ulonglong, half, float, double, longdouble,
- * cfloat, cdouble, clongdouble, datetime, timedelta#
- * #type = npy_bool, npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int,
- * npy_uint, npy_long, npy_ulong, npy_longlong, npy_ulonglong,
- * npy_ushort, npy_float, npy_double, npy_longdouble, npy_cfloat,
- * npy_cdouble, npy_clongdouble, npy_datetime, npy_timedelta#
- */
-
-static void
-mergesort0_@suff@(@type@ *pl, @type@ *pr, @type@ *pw)
-{
- @type@ vp, *pi, *pj, *pk, *pm;
-
- if (pr - pl > SMALL_MERGESORT) {
- /* merge sort */
- pm = pl + ((pr - pl) >> 1);
- mergesort0_@suff@(pl, pm, pw);
- mergesort0_@suff@(pm, pr, pw);
- for (pi = pw, pj = pl; pj < pm;) {
- *pi++ = *pj++;
- }
- pi = pw + (pm - pl);
- pj = pw;
- pk = pl;
- while (pj < pi && pm < pr) {
- if (@TYPE@_LT(*pm, *pj)) {
- *pk++ = *pm++;
- }
- else {
- *pk++ = *pj++;
- }
- }
- while(pj < pi) {
- *pk++ = *pj++;
- }
- }
- else {
- /* insertion sort */
- for (pi = pl + 1; pi < pr; ++pi) {
- vp = *pi;
- pj = pi;
- pk = pi - 1;
- while (pj > pl && @TYPE@_LT(vp, *pk)) {
- *pj-- = *pk--;
- }
- *pj = vp;
- }
- }
-}
-
-
-NPY_NO_EXPORT int
-mergesort_@suff@(void *start, npy_intp num, void *NOT_USED)
-{
- @type@ *pl, *pr, *pw;
-
- pl = start;
- pr = pl + num;
- pw = malloc((num/2) * sizeof(@type@));
- if (pw == NULL) {
- return -NPY_ENOMEM;
- }
- mergesort0_@suff@(pl, pr, pw);
-
- free(pw);
- return 0;
-}
-
-
-static void
-amergesort0_@suff@(npy_intp *pl, npy_intp *pr, @type@ *v, npy_intp *pw)
-{
- @type@ vp;
- npy_intp vi, *pi, *pj, *pk, *pm;
-
- if (pr - pl > SMALL_MERGESORT) {
- /* merge sort */
- pm = pl + ((pr - pl) >> 1);
- amergesort0_@suff@(pl, pm, v, pw);
- amergesort0_@suff@(pm, pr, v, pw);
- for (pi = pw, pj = pl; pj < pm;) {
- *pi++ = *pj++;
- }
- pi = pw + (pm - pl);
- pj = pw;
- pk = pl;
- while (pj < pi && pm < pr) {
- if (@TYPE@_LT(v[*pm], v[*pj])) {
- *pk++ = *pm++;
- }
- else {
- *pk++ = *pj++;
- }
- }
- while(pj < pi) {
- *pk++ = *pj++;
- }
- }
- else {
- /* insertion sort */
- for (pi = pl + 1; pi < pr; ++pi) {
- vi = *pi;
- vp = v[vi];
- pj = pi;
- pk = pi - 1;
- while (pj > pl && @TYPE@_LT(vp, v[*pk])) {
- *pj-- = *pk--;
- }
- *pj = vi;
- }
- }
-}
-
-
-NPY_NO_EXPORT int
-amergesort_@suff@(void *v, npy_intp *tosort, npy_intp num, void *NOT_USED)
-{
- npy_intp *pl, *pr, *pw;
-
- pl = tosort;
- pr = pl + num;
- pw = malloc((num/2) * sizeof(npy_intp));
- if (pw == NULL) {
- return -NPY_ENOMEM;
- }
- amergesort0_@suff@(pl, pr, v, pw);
- free(pw);
-
- return 0;
-}
-
-/**end repeat**/
-
-
-/*
- *****************************************************************************
- ** STRING SORTS **
- *****************************************************************************
- */
-
-
-/**begin repeat
- *
- * #TYPE = STRING, UNICODE#
- * #suff = string, unicode#
- * #type = npy_char, npy_ucs4#
- */
-
-static void
-mergesort0_@suff@(@type@ *pl, @type@ *pr, @type@ *pw, @type@ *vp, size_t len)
-{
- @type@ *pi, *pj, *pk, *pm;
-
- if ((size_t)(pr - pl) > SMALL_MERGESORT*len) {
- /* merge sort */
- pm = pl + (((pr - pl)/len) >> 1)*len;
- mergesort0_@suff@(pl, pm, pw, vp, len);
- mergesort0_@suff@(pm, pr, pw, vp, len);
- @TYPE@_COPY(pw, pl, pm - pl);
- pi = pw + (pm - pl);
- pj = pw;
- pk = pl;
- while (pj < pi && pm < pr) {
- if (@TYPE@_LT(pm, pj, len)) {
- @TYPE@_COPY(pk, pm, len);
- pm += len;
- pk += len;
- }
- else {
- @TYPE@_COPY(pk, pj, len);
- pj += len;
- pk += len;
- }
- }
- @TYPE@_COPY(pk, pj, pi - pj);
- }
- else {
- /* insertion sort */
- for (pi = pl + len; pi < pr; pi += len) {
- @TYPE@_COPY(vp, pi, len);
- pj = pi;
- pk = pi - len;
- while (pj > pl && @TYPE@_LT(vp, pk, len)) {
- @TYPE@_COPY(pj, pk, len);
- pj -= len;
- pk -= len;
- }
- @TYPE@_COPY(pj, vp, len);
- }
- }
-}
-
-
-NPY_NO_EXPORT int
-mergesort_@suff@(void *start, npy_intp num, void *varr)
-{
- PyArrayObject *arr = varr;
- size_t elsize = PyArray_ITEMSIZE(arr);
- size_t len = elsize / sizeof(@type@);
- @type@ *pl, *pr, *pw, *vp;
- int err = 0;
-
- /* Items that have zero size don't make sense to sort */
- if (elsize == 0) {
- return 0;
- }
-
- pl = start;
- pr = pl + num*len;
- pw = malloc((num/2) * elsize);
- if (pw == NULL) {
- err = -NPY_ENOMEM;
- goto fail_0;
- }
- vp = malloc(elsize);
- if (vp == NULL) {
- err = -NPY_ENOMEM;
- goto fail_1;
- }
- mergesort0_@suff@(pl, pr, pw, vp, len);
-
- free(vp);
-fail_1:
- free(pw);
-fail_0:
- return err;
-}
-
-
-static void
-amergesort0_@suff@(npy_intp *pl, npy_intp *pr, @type@ *v, npy_intp *pw, size_t len)
-{
- @type@ *vp;
- npy_intp vi, *pi, *pj, *pk, *pm;
-
- if (pr - pl > SMALL_MERGESORT) {
- /* merge sort */
- pm = pl + ((pr - pl) >> 1);
- amergesort0_@suff@(pl, pm, v, pw, len);
- amergesort0_@suff@(pm, pr, v, pw, len);
- for (pi = pw, pj = pl; pj < pm;) {
- *pi++ = *pj++;
- }
- pi = pw + (pm - pl);
- pj = pw;
- pk = pl;
- while (pj < pi && pm < pr) {
- if (@TYPE@_LT(v + (*pm)*len, v + (*pj)*len, len)) {
- *pk++ = *pm++;
- }
- else {
- *pk++ = *pj++;
- }
- }
- while (pj < pi) {
- *pk++ = *pj++;
- }
- }
- else {
- /* insertion sort */
- for (pi = pl + 1; pi < pr; ++pi) {
- vi = *pi;
- vp = v + vi*len;
- pj = pi;
- pk = pi - 1;
- while (pj > pl && @TYPE@_LT(vp, v + (*pk)*len, len)) {
- *pj-- = *pk--;
- }
- *pj = vi;
- }
- }
-}
-
-
-NPY_NO_EXPORT int
-amergesort_@suff@(void *v, npy_intp *tosort, npy_intp num, void *varr)
-{
- PyArrayObject *arr = varr;
- size_t elsize = PyArray_ITEMSIZE(arr);
- size_t len = elsize / sizeof(@type@);
- npy_intp *pl, *pr, *pw;
-
- /* Items that have zero size don't make sense to sort */
- if (elsize == 0) {
- return 0;
- }
-
- pl = tosort;
- pr = pl + num;
- pw = malloc((num/2) * sizeof(npy_intp));
- if (pw == NULL) {
- return -NPY_ENOMEM;
- }
- amergesort0_@suff@(pl, pr, v, pw, len);
- free(pw);
-
- return 0;
-}
-
-/**end repeat**/
-
-
-/*
- *****************************************************************************
- ** GENERIC SORT **
- *****************************************************************************
- */
-
-
-static void
-npy_mergesort0(char *pl, char *pr, char *pw, char *vp, npy_intp elsize,
- PyArray_CompareFunc *cmp, PyArrayObject *arr)
-{
- char *pi, *pj, *pk, *pm;
-
- if (pr - pl > SMALL_MERGESORT*elsize) {
- /* merge sort */
- pm = pl + (((pr - pl)/elsize) >> 1)*elsize;
- npy_mergesort0(pl, pm, pw, vp, elsize, cmp, arr);
- npy_mergesort0(pm, pr, pw, vp, elsize, cmp, arr);
- GENERIC_COPY(pw, pl, pm - pl);
- pi = pw + (pm - pl);
- pj = pw;
- pk = pl;
- while (pj < pi && pm < pr) {
- if (cmp(pm, pj, arr) < 0) {
- GENERIC_COPY(pk, pm, elsize);
- pm += elsize;
- pk += elsize;
- }
- else {
- GENERIC_COPY(pk, pj, elsize);
- pj += elsize;
- pk += elsize;
- }
- }
- GENERIC_COPY(pk, pj, pi - pj);
- }
- else {
- /* insertion sort */
- for (pi = pl + elsize; pi < pr; pi += elsize) {
- GENERIC_COPY(vp, pi, elsize);
- pj = pi;
- pk = pi - elsize;
- while (pj > pl && cmp(vp, pk, arr) < 0) {
- GENERIC_COPY(pj, pk, elsize);
- pj -= elsize;
- pk -= elsize;
- }
- GENERIC_COPY(pj, vp, elsize);
- }
- }
-}
-
-
-NPY_NO_EXPORT int
-npy_mergesort(void *start, npy_intp num, void *varr)
-{
- PyArrayObject *arr = varr;
- npy_intp elsize = PyArray_ITEMSIZE(arr);
- PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare;
- char *pl = start;
- char *pr = pl + num*elsize;
- char *pw;
- char *vp;
- int err = -NPY_ENOMEM;
-
- /* Items that have zero size don't make sense to sort */
- if (elsize == 0) {
- return 0;
- }
-
- pw = malloc((num >> 1) *elsize);
- vp = malloc(elsize);
-
- if (pw != NULL && vp != NULL) {
- npy_mergesort0(pl, pr, pw, vp, elsize, cmp, arr);
- err = 0;
- }
-
- free(vp);
- free(pw);
-
- return err;
-}
-
-
-static void
-npy_amergesort0(npy_intp *pl, npy_intp *pr, char *v, npy_intp *pw,
- npy_intp elsize, PyArray_CompareFunc *cmp, PyArrayObject *arr)
-{
- char *vp;
- npy_intp vi, *pi, *pj, *pk, *pm;
-
- if (pr - pl > SMALL_MERGESORT) {
- /* merge sort */
- pm = pl + ((pr - pl) >> 1);
- npy_amergesort0(pl, pm, v, pw, elsize, cmp, arr);
- npy_amergesort0(pm, pr, v, pw, elsize, cmp, arr);
- for (pi = pw, pj = pl; pj < pm;) {
- *pi++ = *pj++;
- }
- pi = pw + (pm - pl);
- pj = pw;
- pk = pl;
- while (pj < pi && pm < pr) {
- if (cmp(v + (*pm)*elsize, v + (*pj)*elsize, arr) < 0) {
- *pk++ = *pm++;
- }
- else {
- *pk++ = *pj++;
- }
- }
- while (pj < pi) {
- *pk++ = *pj++;
- }
- }
- else {
- /* insertion sort */
- for (pi = pl + 1; pi < pr; ++pi) {
- vi = *pi;
- vp = v + vi*elsize;
- pj = pi;
- pk = pi - 1;
- while (pj > pl && cmp(vp, v + (*pk)*elsize, arr) < 0) {
- *pj-- = *pk--;
- }
- *pj = vi;
- }
- }
-}
-
-
-NPY_NO_EXPORT int
-npy_amergesort(void *v, npy_intp *tosort, npy_intp num, void *varr)
-{
- PyArrayObject *arr = varr;
- npy_intp elsize = PyArray_ITEMSIZE(arr);
- PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare;
- npy_intp *pl, *pr, *pw;
-
- /* Items that have zero size don't make sense to sort */
- if (elsize == 0) {
- return 0;
- }
-
- pl = tosort;
- pr = pl + num;
- pw = malloc((num >> 1) * sizeof(npy_intp));
- if (pw == NULL) {
- return -NPY_ENOMEM;
- }
- npy_amergesort0(pl, pr, v, pw, elsize, cmp, arr);
- free(pw);
-
- return 0;
-}
diff --git a/numpy/core/src/npysort/mergesort.cpp b/numpy/core/src/npysort/mergesort.cpp
new file mode 100644
index 000000000..f892dd185
--- /dev/null
+++ b/numpy/core/src/npysort/mergesort.cpp
@@ -0,0 +1,733 @@
+/* -*- c -*- */
+
+/*
+ * The purpose of this module is to add faster sort functions
+ * that are type-specific. This is done by altering the
+ * function table for the builtin descriptors.
+ *
+ * These sorting functions are copied almost directly from numarray
+ * with a few modifications (complex comparisons compare the imaginary
+ * part if the real parts are equal, for example), and the names
+ * are changed.
+ *
+ * The original sorting code is due to Charles R. Harris who wrote
+ * it for numarray.
+ */
+
+/*
+ * Quick sort is usually the fastest, but the worst case scenario can
+ * be slower than the merge and heap sorts. The merge sort requires
+ * extra memory and so for large arrays may not be useful.
+ *
+ * The merge sort is *stable*, meaning that equal components
+ * are unmoved from their entry versions, so it can be used to
+ * implement lexigraphic sorting on multiple keys.
+ *
+ * The heap sort is included for completeness.
+ */
+
+#define NPY_NO_DEPRECATED_API NPY_API_VERSION
+
+#include "npy_sort.h"
+#include "npysort_common.h"
+#include "numpy_tag.h"
+
+#include <cstdlib>
+
+#define NOT_USED NPY_UNUSED(unused)
+#define PYA_QS_STACK 100
+#define SMALL_QUICKSORT 15
+#define SMALL_MERGESORT 20
+#define SMALL_STRING 16
+
+/*
+ *****************************************************************************
+ ** NUMERIC SORTS **
+ *****************************************************************************
+ */
+
+template <typename Tag, typename type>
+static void
+mergesort0_(type *pl, type *pr, type *pw)
+{
+ type vp, *pi, *pj, *pk, *pm;
+
+ if (pr - pl > SMALL_MERGESORT) {
+ /* merge sort */
+ pm = pl + ((pr - pl) >> 1);
+ mergesort0_<Tag>(pl, pm, pw);
+ mergesort0_<Tag>(pm, pr, pw);
+ for (pi = pw, pj = pl; pj < pm;) {
+ *pi++ = *pj++;
+ }
+ pi = pw + (pm - pl);
+ pj = pw;
+ pk = pl;
+ while (pj < pi && pm < pr) {
+ if (Tag::less(*pm, *pj)) {
+ *pk++ = *pm++;
+ }
+ else {
+ *pk++ = *pj++;
+ }
+ }
+ while (pj < pi) {
+ *pk++ = *pj++;
+ }
+ }
+ else {
+ /* insertion sort */
+ for (pi = pl + 1; pi < pr; ++pi) {
+ vp = *pi;
+ pj = pi;
+ pk = pi - 1;
+ while (pj > pl && Tag::less(vp, *pk)) {
+ *pj-- = *pk--;
+ }
+ *pj = vp;
+ }
+ }
+}
+
+template <typename Tag, typename type>
+NPY_NO_EXPORT int
+mergesort_(type *start, npy_intp num)
+{
+ type *pl, *pr, *pw;
+
+ pl = start;
+ pr = pl + num;
+ pw = (type *)malloc((num / 2) * sizeof(type));
+ if (pw == NULL) {
+ return -NPY_ENOMEM;
+ }
+ mergesort0_<Tag>(pl, pr, pw);
+
+ free(pw);
+ return 0;
+}
+
+template <typename Tag, typename type>
+static void
+amergesort0_(npy_intp *pl, npy_intp *pr, type *v, npy_intp *pw)
+{
+ type vp;
+ npy_intp vi, *pi, *pj, *pk, *pm;
+
+ if (pr - pl > SMALL_MERGESORT) {
+ /* merge sort */
+ pm = pl + ((pr - pl) >> 1);
+ amergesort0_<Tag>(pl, pm, v, pw);
+ amergesort0_<Tag>(pm, pr, v, pw);
+ for (pi = pw, pj = pl; pj < pm;) {
+ *pi++ = *pj++;
+ }
+ pi = pw + (pm - pl);
+ pj = pw;
+ pk = pl;
+ while (pj < pi && pm < pr) {
+ if (Tag::less(v[*pm], v[*pj])) {
+ *pk++ = *pm++;
+ }
+ else {
+ *pk++ = *pj++;
+ }
+ }
+ while (pj < pi) {
+ *pk++ = *pj++;
+ }
+ }
+ else {
+ /* insertion sort */
+ for (pi = pl + 1; pi < pr; ++pi) {
+ vi = *pi;
+ vp = v[vi];
+ pj = pi;
+ pk = pi - 1;
+ while (pj > pl && Tag::less(vp, v[*pk])) {
+ *pj-- = *pk--;
+ }
+ *pj = vi;
+ }
+ }
+}
+
+template <typename Tag, typename type>
+NPY_NO_EXPORT int
+amergesort_(type *v, npy_intp *tosort, npy_intp num)
+{
+ npy_intp *pl, *pr, *pw;
+
+ pl = tosort;
+ pr = pl + num;
+ pw = (npy_intp *)malloc((num / 2) * sizeof(npy_intp));
+ if (pw == NULL) {
+ return -NPY_ENOMEM;
+ }
+ amergesort0_<Tag>(pl, pr, v, pw);
+ free(pw);
+
+ return 0;
+}
+
+/*
+ *****************************************************************************
+ ** STRING SORTS **
+ *****************************************************************************
+ */
+
+template <typename Tag, typename type>
+static void
+mergesort0_(type *pl, type *pr, type *pw, type *vp, size_t len)
+{
+ type *pi, *pj, *pk, *pm;
+
+ if ((size_t)(pr - pl) > SMALL_MERGESORT * len) {
+ /* merge sort */
+ pm = pl + (((pr - pl) / len) >> 1) * len;
+ mergesort0_<Tag>(pl, pm, pw, vp, len);
+ mergesort0_<Tag>(pm, pr, pw, vp, len);
+ Tag::copy(pw, pl, pm - pl);
+ pi = pw + (pm - pl);
+ pj = pw;
+ pk = pl;
+ while (pj < pi && pm < pr) {
+ if (Tag::less(pm, pj, len)) {
+ Tag::copy(pk, pm, len);
+ pm += len;
+ pk += len;
+ }
+ else {
+ Tag::copy(pk, pj, len);
+ pj += len;
+ pk += len;
+ }
+ }
+ Tag::copy(pk, pj, pi - pj);
+ }
+ else {
+ /* insertion sort */
+ for (pi = pl + len; pi < pr; pi += len) {
+ Tag::copy(vp, pi, len);
+ pj = pi;
+ pk = pi - len;
+ while (pj > pl && Tag::less(vp, pk, len)) {
+ Tag::copy(pj, pk, len);
+ pj -= len;
+ pk -= len;
+ }
+ Tag::copy(pj, vp, len);
+ }
+ }
+}
+
+template <typename Tag, typename type>
+static int
+string_mergesort_(type *start, npy_intp num, void *varr)
+{
+ PyArrayObject *arr = (PyArrayObject *)varr;
+ size_t elsize = PyArray_ITEMSIZE(arr);
+ size_t len = elsize / sizeof(type);
+ type *pl, *pr, *pw, *vp;
+ int err = 0;
+
+ /* Items that have zero size don't make sense to sort */
+ if (elsize == 0) {
+ return 0;
+ }
+
+ pl = start;
+ pr = pl + num * len;
+ pw = (type *)malloc((num / 2) * elsize);
+ if (pw == NULL) {
+ err = -NPY_ENOMEM;
+ goto fail_0;
+ }
+ vp = (type *)malloc(elsize);
+ if (vp == NULL) {
+ err = -NPY_ENOMEM;
+ goto fail_1;
+ }
+ mergesort0_<Tag>(pl, pr, pw, vp, len);
+
+ free(vp);
+fail_1:
+ free(pw);
+fail_0:
+ return err;
+}
+
+template <typename Tag, typename type>
+static void
+amergesort0_(npy_intp *pl, npy_intp *pr, type *v, npy_intp *pw, size_t len)
+{
+ type *vp;
+ npy_intp vi, *pi, *pj, *pk, *pm;
+
+ if (pr - pl > SMALL_MERGESORT) {
+ /* merge sort */
+ pm = pl + ((pr - pl) >> 1);
+ amergesort0_<Tag>(pl, pm, v, pw, len);
+ amergesort0_<Tag>(pm, pr, v, pw, len);
+ for (pi = pw, pj = pl; pj < pm;) {
+ *pi++ = *pj++;
+ }
+ pi = pw + (pm - pl);
+ pj = pw;
+ pk = pl;
+ while (pj < pi && pm < pr) {
+ if (Tag::less(v + (*pm) * len, v + (*pj) * len, len)) {
+ *pk++ = *pm++;
+ }
+ else {
+ *pk++ = *pj++;
+ }
+ }
+ while (pj < pi) {
+ *pk++ = *pj++;
+ }
+ }
+ else {
+ /* insertion sort */
+ for (pi = pl + 1; pi < pr; ++pi) {
+ vi = *pi;
+ vp = v + vi * len;
+ pj = pi;
+ pk = pi - 1;
+ while (pj > pl && Tag::less(vp, v + (*pk) * len, len)) {
+ *pj-- = *pk--;
+ }
+ *pj = vi;
+ }
+ }
+}
+
+template <typename Tag, typename type>
+static int
+string_amergesort_(type *v, npy_intp *tosort, npy_intp num, void *varr)
+{
+ PyArrayObject *arr = (PyArrayObject *)varr;
+ size_t elsize = PyArray_ITEMSIZE(arr);
+ size_t len = elsize / sizeof(type);
+ npy_intp *pl, *pr, *pw;
+
+ /* Items that have zero size don't make sense to sort */
+ if (elsize == 0) {
+ return 0;
+ }
+
+ pl = tosort;
+ pr = pl + num;
+ pw = (npy_intp *)malloc((num / 2) * sizeof(npy_intp));
+ if (pw == NULL) {
+ return -NPY_ENOMEM;
+ }
+ amergesort0_<Tag>(pl, pr, v, pw, len);
+ free(pw);
+
+ return 0;
+}
+
+/*
+ *****************************************************************************
+ ** GENERIC SORT **
+ *****************************************************************************
+ */
+
+static void
+npy_mergesort0(char *pl, char *pr, char *pw, char *vp, npy_intp elsize,
+ PyArray_CompareFunc *cmp, PyArrayObject *arr)
+{
+ char *pi, *pj, *pk, *pm;
+
+ if (pr - pl > SMALL_MERGESORT * elsize) {
+ /* merge sort */
+ pm = pl + (((pr - pl) / elsize) >> 1) * elsize;
+ npy_mergesort0(pl, pm, pw, vp, elsize, cmp, arr);
+ npy_mergesort0(pm, pr, pw, vp, elsize, cmp, arr);
+ GENERIC_COPY(pw, pl, pm - pl);
+ pi = pw + (pm - pl);
+ pj = pw;
+ pk = pl;
+ while (pj < pi && pm < pr) {
+ if (cmp(pm, pj, arr) < 0) {
+ GENERIC_COPY(pk, pm, elsize);
+ pm += elsize;
+ pk += elsize;
+ }
+ else {
+ GENERIC_COPY(pk, pj, elsize);
+ pj += elsize;
+ pk += elsize;
+ }
+ }
+ GENERIC_COPY(pk, pj, pi - pj);
+ }
+ else {
+ /* insertion sort */
+ for (pi = pl + elsize; pi < pr; pi += elsize) {
+ GENERIC_COPY(vp, pi, elsize);
+ pj = pi;
+ pk = pi - elsize;
+ while (pj > pl && cmp(vp, pk, arr) < 0) {
+ GENERIC_COPY(pj, pk, elsize);
+ pj -= elsize;
+ pk -= elsize;
+ }
+ GENERIC_COPY(pj, vp, elsize);
+ }
+ }
+}
+
+NPY_NO_EXPORT int
+npy_mergesort(void *start, npy_intp num, void *varr)
+{
+ PyArrayObject *arr = (PyArrayObject *)varr;
+ npy_intp elsize = PyArray_ITEMSIZE(arr);
+ PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare;
+ char *pl = (char *)start;
+ char *pr = pl + num * elsize;
+ char *pw;
+ char *vp;
+ int err = -NPY_ENOMEM;
+
+ /* Items that have zero size don't make sense to sort */
+ if (elsize == 0) {
+ return 0;
+ }
+
+ pw = (char *)malloc((num >> 1) * elsize);
+ vp = (char *)malloc(elsize);
+
+ if (pw != NULL && vp != NULL) {
+ npy_mergesort0(pl, pr, pw, vp, elsize, cmp, arr);
+ err = 0;
+ }
+
+ free(vp);
+ free(pw);
+
+ return err;
+}
+
+static void
+npy_amergesort0(npy_intp *pl, npy_intp *pr, char *v, npy_intp *pw,
+ npy_intp elsize, PyArray_CompareFunc *cmp, PyArrayObject *arr)
+{
+ char *vp;
+ npy_intp vi, *pi, *pj, *pk, *pm;
+
+ if (pr - pl > SMALL_MERGESORT) {
+ /* merge sort */
+ pm = pl + ((pr - pl) >> 1);
+ npy_amergesort0(pl, pm, v, pw, elsize, cmp, arr);
+ npy_amergesort0(pm, pr, v, pw, elsize, cmp, arr);
+ for (pi = pw, pj = pl; pj < pm;) {
+ *pi++ = *pj++;
+ }
+ pi = pw + (pm - pl);
+ pj = pw;
+ pk = pl;
+ while (pj < pi && pm < pr) {
+ if (cmp(v + (*pm) * elsize, v + (*pj) * elsize, arr) < 0) {
+ *pk++ = *pm++;
+ }
+ else {
+ *pk++ = *pj++;
+ }
+ }
+ while (pj < pi) {
+ *pk++ = *pj++;
+ }
+ }
+ else {
+ /* insertion sort */
+ for (pi = pl + 1; pi < pr; ++pi) {
+ vi = *pi;
+ vp = v + vi * elsize;
+ pj = pi;
+ pk = pi - 1;
+ while (pj > pl && cmp(vp, v + (*pk) * elsize, arr) < 0) {
+ *pj-- = *pk--;
+ }
+ *pj = vi;
+ }
+ }
+}
+
+NPY_NO_EXPORT int
+npy_amergesort(void *v, npy_intp *tosort, npy_intp num, void *varr)
+{
+ PyArrayObject *arr = (PyArrayObject *)varr;
+ npy_intp elsize = PyArray_ITEMSIZE(arr);
+ PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare;
+ npy_intp *pl, *pr, *pw;
+
+ /* Items that have zero size don't make sense to sort */
+ if (elsize == 0) {
+ return 0;
+ }
+
+ pl = tosort;
+ pr = pl + num;
+ pw = (npy_intp *)malloc((num >> 1) * sizeof(npy_intp));
+ if (pw == NULL) {
+ return -NPY_ENOMEM;
+ }
+ npy_amergesort0(pl, pr, (char *)v, pw, elsize, cmp, arr);
+ free(pw);
+
+ return 0;
+}
+
+/***************************************
+ * C > C++ dispatch
+ ***************************************/
+NPY_NO_EXPORT int
+mergesort_bool(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return mergesort_<npy::bool_tag>((npy_bool *)start, num);
+}
+NPY_NO_EXPORT int
+mergesort_byte(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return mergesort_<npy::byte_tag>((npy_byte *)start, num);
+}
+NPY_NO_EXPORT int
+mergesort_ubyte(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return mergesort_<npy::ubyte_tag>((npy_ubyte *)start, num);
+}
+NPY_NO_EXPORT int
+mergesort_short(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return mergesort_<npy::short_tag>((npy_short *)start, num);
+}
+NPY_NO_EXPORT int
+mergesort_ushort(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return mergesort_<npy::ushort_tag>((npy_ushort *)start, num);
+}
+NPY_NO_EXPORT int
+mergesort_int(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return mergesort_<npy::int_tag>((npy_int *)start, num);
+}
+NPY_NO_EXPORT int
+mergesort_uint(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return mergesort_<npy::uint_tag>((npy_uint *)start, num);
+}
+NPY_NO_EXPORT int
+mergesort_long(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return mergesort_<npy::long_tag>((npy_long *)start, num);
+}
+NPY_NO_EXPORT int
+mergesort_ulong(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return mergesort_<npy::ulong_tag>((npy_ulong *)start, num);
+}
+NPY_NO_EXPORT int
+mergesort_longlong(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return mergesort_<npy::longlong_tag>((npy_longlong *)start, num);
+}
+NPY_NO_EXPORT int
+mergesort_ulonglong(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return mergesort_<npy::ulonglong_tag>((npy_ulonglong *)start, num);
+}
+NPY_NO_EXPORT int
+mergesort_half(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return mergesort_<npy::half_tag>((npy_half *)start, num);
+}
+NPY_NO_EXPORT int
+mergesort_float(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return mergesort_<npy::float_tag>((npy_float *)start, num);
+}
+NPY_NO_EXPORT int
+mergesort_double(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return mergesort_<npy::double_tag>((npy_double *)start, num);
+}
+NPY_NO_EXPORT int
+mergesort_longdouble(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return mergesort_<npy::longdouble_tag>((npy_longdouble *)start, num);
+}
+NPY_NO_EXPORT int
+mergesort_cfloat(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return mergesort_<npy::cfloat_tag>((npy_cfloat *)start, num);
+}
+NPY_NO_EXPORT int
+mergesort_cdouble(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return mergesort_<npy::cdouble_tag>((npy_cdouble *)start, num);
+}
+NPY_NO_EXPORT int
+mergesort_clongdouble(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return mergesort_<npy::clongdouble_tag>((npy_clongdouble *)start, num);
+}
+NPY_NO_EXPORT int
+mergesort_datetime(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return mergesort_<npy::datetime_tag>((npy_datetime *)start, num);
+}
+NPY_NO_EXPORT int
+mergesort_timedelta(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return mergesort_<npy::timedelta_tag>((npy_timedelta *)start, num);
+}
+
+NPY_NO_EXPORT int
+amergesort_bool(void *start, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return amergesort_<npy::bool_tag>((npy_bool *)start, tosort, num);
+}
+NPY_NO_EXPORT int
+amergesort_byte(void *start, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return amergesort_<npy::byte_tag>((npy_byte *)start, tosort, num);
+}
+NPY_NO_EXPORT int
+amergesort_ubyte(void *start, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return amergesort_<npy::ubyte_tag>((npy_ubyte *)start, tosort, num);
+}
+NPY_NO_EXPORT int
+amergesort_short(void *start, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return amergesort_<npy::short_tag>((npy_short *)start, tosort, num);
+}
+NPY_NO_EXPORT int
+amergesort_ushort(void *start, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return amergesort_<npy::ushort_tag>((npy_ushort *)start, tosort, num);
+}
+NPY_NO_EXPORT int
+amergesort_int(void *start, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return amergesort_<npy::int_tag>((npy_int *)start, tosort, num);
+}
+NPY_NO_EXPORT int
+amergesort_uint(void *start, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return amergesort_<npy::uint_tag>((npy_uint *)start, tosort, num);
+}
+NPY_NO_EXPORT int
+amergesort_long(void *start, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return amergesort_<npy::long_tag>((npy_long *)start, tosort, num);
+}
+NPY_NO_EXPORT int
+amergesort_ulong(void *start, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return amergesort_<npy::ulong_tag>((npy_ulong *)start, tosort, num);
+}
+NPY_NO_EXPORT int
+amergesort_longlong(void *start, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return amergesort_<npy::longlong_tag>((npy_longlong *)start, tosort, num);
+}
+NPY_NO_EXPORT int
+amergesort_ulonglong(void *start, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return amergesort_<npy::ulonglong_tag>((npy_ulonglong *)start, tosort,
+ num);
+}
+NPY_NO_EXPORT int
+amergesort_half(void *start, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return amergesort_<npy::half_tag>((npy_half *)start, tosort, num);
+}
+NPY_NO_EXPORT int
+amergesort_float(void *start, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return amergesort_<npy::float_tag>((npy_float *)start, tosort, num);
+}
+NPY_NO_EXPORT int
+amergesort_double(void *start, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return amergesort_<npy::double_tag>((npy_double *)start, tosort, num);
+}
+NPY_NO_EXPORT int
+amergesort_longdouble(void *start, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return amergesort_<npy::longdouble_tag>((npy_longdouble *)start, tosort,
+ num);
+}
+NPY_NO_EXPORT int
+amergesort_cfloat(void *start, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return amergesort_<npy::cfloat_tag>((npy_cfloat *)start, tosort, num);
+}
+NPY_NO_EXPORT int
+amergesort_cdouble(void *start, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return amergesort_<npy::cdouble_tag>((npy_cdouble *)start, tosort, num);
+}
+NPY_NO_EXPORT int
+amergesort_clongdouble(void *start, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return amergesort_<npy::clongdouble_tag>((npy_clongdouble *)start, tosort,
+ num);
+}
+NPY_NO_EXPORT int
+amergesort_datetime(void *start, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return amergesort_<npy::datetime_tag>((npy_datetime *)start, tosort, num);
+}
+NPY_NO_EXPORT int
+amergesort_timedelta(void *start, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return amergesort_<npy::timedelta_tag>((npy_timedelta *)start, tosort,
+ num);
+}
+
+NPY_NO_EXPORT int
+mergesort_string(void *start, npy_intp num, void *varr)
+{
+ return string_mergesort_<npy::string_tag>((npy_char *)start, num, varr);
+}
+NPY_NO_EXPORT int
+mergesort_unicode(void *start, npy_intp num, void *varr)
+{
+ return string_mergesort_<npy::unicode_tag>((npy_ucs4 *)start, num, varr);
+}
+NPY_NO_EXPORT int
+amergesort_string(void *v, npy_intp *tosort, npy_intp num, void *varr)
+{
+ return string_amergesort_<npy::string_tag>((npy_char *)v, tosort, num,
+ varr);
+}
+NPY_NO_EXPORT int
+amergesort_unicode(void *v, npy_intp *tosort, npy_intp num, void *varr)
+{
+ return string_amergesort_<npy::unicode_tag>((npy_ucs4 *)v, tosort, num,
+ varr);
+}
diff --git a/numpy/core/src/npysort/npysort_common.h b/numpy/core/src/npysort/npysort_common.h
index a537fcd08..ab9f456b6 100644
--- a/numpy/core/src/npysort/npysort_common.h
+++ b/numpy/core/src/npysort/npysort_common.h
@@ -259,7 +259,7 @@ CLONGDOUBLE_LT(npy_clongdouble a, npy_clongdouble b)
NPY_INLINE static void
-STRING_COPY(char *s1, char *s2, size_t len)
+STRING_COPY(char *s1, char const*s2, size_t len)
{
memcpy(s1, s2, len);
}
@@ -295,7 +295,7 @@ STRING_LT(const char *s1, const char *s2, size_t len)
NPY_INLINE static void
-UNICODE_COPY(npy_ucs4 *s1, npy_ucs4 *s2, size_t len)
+UNICODE_COPY(npy_ucs4 *s1, npy_ucs4 const *s2, size_t len)
{
while(len--) {
*s1++ = *s2++;
diff --git a/numpy/core/src/npysort/selection.c.src b/numpy/core/src/npysort/selection.c.src
deleted file mode 100644
index 0e285b320..000000000
--- a/numpy/core/src/npysort/selection.c.src
+++ /dev/null
@@ -1,419 +0,0 @@
-/* -*- c -*- */
-
-/*
- *
- * The code is loosely based on the quickselect from
- * Nicolas Devillard - 1998 public domain
- * http://ndevilla.free.fr/median/median/
- *
- * Quick select with median of 3 pivot is usually the fastest,
- * but the worst case scenario can be quadratic complexity,
- * e.g. np.roll(np.arange(x), x / 2)
- * To avoid this if it recurses too much it falls back to the
- * worst case linear median of median of group 5 pivot strategy.
- */
-
-
-#define NPY_NO_DEPRECATED_API NPY_API_VERSION
-
-#include "npy_sort.h"
-#include "npysort_common.h"
-#include "numpy/npy_math.h"
-#include "npy_partition.h"
-#include <stdlib.h>
-
-#define NOT_USED NPY_UNUSED(unused)
-
-
-/*
- *****************************************************************************
- ** NUMERIC SORTS **
- *****************************************************************************
- */
-
-
-static NPY_INLINE void store_pivot(npy_intp pivot, npy_intp kth,
- npy_intp * pivots, npy_intp * npiv)
-{
- if (pivots == NULL) {
- return;
- }
-
- /*
- * If pivot is the requested kth store it, overwriting other pivots if
- * required. This must be done so iterative partition can work without
- * manually shifting lower data offset by kth each time
- */
- if (pivot == kth && *npiv == NPY_MAX_PIVOT_STACK) {
- pivots[*npiv - 1] = pivot;
- }
- /*
- * we only need pivots larger than current kth, larger pivots are not
- * useful as partitions on smaller kth would reorder the stored pivots
- */
- else if (pivot >= kth && *npiv < NPY_MAX_PIVOT_STACK) {
- pivots[*npiv] = pivot;
- (*npiv) += 1;
- }
-}
-
-/**begin repeat
- *
- * #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG,
- * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE,
- * CFLOAT, CDOUBLE, CLONGDOUBLE#
- * #suff = bool, byte, ubyte, short, ushort, int, uint, long, ulong,
- * longlong, ulonglong, half, float, double, longdouble,
- * cfloat, cdouble, clongdouble#
- * #type = npy_bool, npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int,
- * npy_uint, npy_long, npy_ulong, npy_longlong, npy_ulonglong,
- * npy_ushort, npy_float, npy_double, npy_longdouble, npy_cfloat,
- * npy_cdouble, npy_clongdouble#
- * #inexact = 0*11, 1*7#
- */
-
-static npy_intp
-amedian_of_median5_@suff@(@type@ *v, npy_intp* tosort, const npy_intp num,
- npy_intp * pivots,
- npy_intp * npiv);
-
-static npy_intp
-median_of_median5_@suff@(@type@ *v, const npy_intp num,
- npy_intp * pivots,
- npy_intp * npiv);
-
-/**begin repeat1
- * #name = , a#
- * #idx = , tosort#
- * #arg = 0, 1#
- */
-#if @arg@
-/* helper macros to avoid duplication of direct/indirect selection */
-#define IDX(x) tosort[x]
-#define SORTEE(x) tosort[x]
-#define SWAP INTP_SWAP
-#define MEDIAN3_SWAP(v, tosort, low, mid, high) \
- amedian3_swap_@suff@(v, tosort, low, mid, high)
-#define MEDIAN5(v, tosort, subleft) \
- amedian5_@suff@(v, tosort + subleft)
-#define UNGUARDED_PARTITION(v, tosort, pivot, ll, hh) \
- aunguarded_partition_@suff@(v, tosort, pivot, ll, hh)
-#define INTROSELECT(v, tosort, num, kth, pivots, npiv) \
- aintroselect_@suff@(v, tosort, nmed, nmed / 2, pivots, npiv, NULL)
-#define DUMBSELECT(v, tosort, left, num, kth) \
- adumb_select_@suff@(v, tosort + left, num, kth)
-#else
-#define IDX(x) (x)
-#define SORTEE(x) v[x]
-#define SWAP @TYPE@_SWAP
-#define MEDIAN3_SWAP(v, tosort, low, mid, high) \
- median3_swap_@suff@(v, low, mid, high)
-#define MEDIAN5(v, tosort, subleft) \
- median5_@suff@(v + subleft)
-#define UNGUARDED_PARTITION(v, tosort, pivot, ll, hh) \
- unguarded_partition_@suff@(v, pivot, ll, hh)
-#define INTROSELECT(v, tosort, num, kth, pivots, npiv) \
- introselect_@suff@(v, nmed, nmed / 2, pivots, npiv, NULL)
-#define DUMBSELECT(v, tosort, left, num, kth) \
- dumb_select_@suff@(v + left, num, kth)
-#endif
-
-
-/*
- * median of 3 pivot strategy
- * gets min and median and moves median to low and min to low + 1
- * for efficient partitioning, see unguarded_partition
- */
-static NPY_INLINE void
-@name@median3_swap_@suff@(@type@ * v,
-#if @arg@
- npy_intp * tosort,
-#endif
- npy_intp low, npy_intp mid, npy_intp high)
-{
- if (@TYPE@_LT(v[IDX(high)], v[IDX(mid)]))
- SWAP(SORTEE(high), SORTEE(mid));
- if (@TYPE@_LT(v[IDX(high)], v[IDX(low)]))
- SWAP(SORTEE(high), SORTEE(low));
- /* move pivot to low */
- if (@TYPE@_LT(v[IDX(low)], v[IDX(mid)]))
- SWAP(SORTEE(low), SORTEE(mid));
- /* move 3-lowest element to low + 1 */
- SWAP(SORTEE(mid), SORTEE(low + 1));
-}
-
-
-/* select index of median of five elements */
-static npy_intp @name@median5_@suff@(
-#if @arg@
- const @type@ * v, npy_intp * tosort
-#else
- @type@ * v
-#endif
- )
-{
- /* could be optimized as we only need the index (no swaps) */
- if (@TYPE@_LT(v[IDX(1)], v[IDX(0)])) {
- SWAP(SORTEE(1), SORTEE(0));
- }
- if (@TYPE@_LT(v[IDX(4)], v[IDX(3)])) {
- SWAP(SORTEE(4), SORTEE(3));
- }
- if (@TYPE@_LT(v[IDX(3)], v[IDX(0)])) {
- SWAP(SORTEE(3), SORTEE(0));
- }
- if (@TYPE@_LT(v[IDX(4)], v[IDX(1)])) {
- SWAP(SORTEE(4), SORTEE(1));
- }
- if (@TYPE@_LT(v[IDX(2)], v[IDX(1)])) {
- SWAP(SORTEE(2), SORTEE(1));
- }
- if (@TYPE@_LT(v[IDX(3)], v[IDX(2)])) {
- if (@TYPE@_LT(v[IDX(3)], v[IDX(1)])) {
- return 1;
- }
- else {
- return 3;
- }
- }
- else {
- /* v[1] and v[2] swapped into order above */
- return 2;
- }
-}
-
-
-/*
- * partition and return the index were the pivot belongs
- * the data must have following property to avoid bound checks:
- * ll ... hh
- * lower-than-pivot [x x x x] larger-than-pivot
- */
-static NPY_INLINE void
-@name@unguarded_partition_@suff@(@type@ * v,
-#if @arg@
- npy_intp * tosort,
-#endif
- const @type@ pivot,
- npy_intp * ll, npy_intp * hh)
-{
- for (;;) {
- do (*ll)++; while (@TYPE@_LT(v[IDX(*ll)], pivot));
- do (*hh)--; while (@TYPE@_LT(pivot, v[IDX(*hh)]));
-
- if (*hh < *ll)
- break;
-
- SWAP(SORTEE(*ll), SORTEE(*hh));
- }
-}
-
-
-/*
- * select median of median of blocks of 5
- * if used as partition pivot it splits the range into at least 30%/70%
- * allowing linear time worstcase quickselect
- */
-static npy_intp
-@name@median_of_median5_@suff@(@type@ *v,
-#if @arg@
- npy_intp* tosort,
-#endif
- const npy_intp num,
- npy_intp * pivots,
- npy_intp * npiv)
-{
- npy_intp i, subleft;
- npy_intp right = num - 1;
- npy_intp nmed = (right + 1) / 5;
- for (i = 0, subleft = 0; i < nmed; i++, subleft += 5) {
- npy_intp m = MEDIAN5(v, tosort, subleft);
- SWAP(SORTEE(subleft + m), SORTEE(i));
- }
-
- if (nmed > 2)
- INTROSELECT(v, tosort, nmed, nmed / 2, pivots, npiv);
- return nmed / 2;
-}
-
-
-/*
- * N^2 selection, fast only for very small kth
- * useful for close multiple partitions
- * (e.g. even element median, interpolating percentile)
- */
-static int
-@name@dumb_select_@suff@(@type@ *v,
-#if @arg@
- npy_intp * tosort,
-#endif
- npy_intp num, npy_intp kth)
-{
- npy_intp i;
- for (i = 0; i <= kth; i++) {
- npy_intp minidx = i;
- @type@ minval = v[IDX(i)];
- npy_intp k;
- for (k = i + 1; k < num; k++) {
- if (@TYPE@_LT(v[IDX(k)], minval)) {
- minidx = k;
- minval = v[IDX(k)];
- }
- }
- SWAP(SORTEE(i), SORTEE(minidx));
- }
-
- return 0;
-}
-
-
-/*
- * iterative median of 3 quickselect with cutoff to median-of-medians-of5
- * receives stack of already computed pivots in v to minimize the
- * partition size were kth is searched in
- *
- * area that needs partitioning in [...]
- * kth 0: [8 7 6 5 4 3 2 1 0] -> med3 partitions elements [4, 2, 0]
- * 0 1 2 3 4 8 7 5 6 -> pop requested kth -> stack [4, 2]
- * kth 3: 0 1 2 [3] 4 8 7 5 6 -> stack [4]
- * kth 5: 0 1 2 3 4 [8 7 5 6] -> stack [6]
- * kth 8: 0 1 2 3 4 5 6 [8 7] -> stack []
- *
- */
-NPY_NO_EXPORT int
-@name@introselect_@suff@(@type@ *v,
-#if @arg@
- npy_intp* tosort,
-#endif
- npy_intp num, npy_intp kth,
- npy_intp * pivots,
- npy_intp * npiv,
- void *NOT_USED)
-{
- npy_intp low = 0;
- npy_intp high = num - 1;
- int depth_limit;
-
- if (npiv == NULL)
- pivots = NULL;
-
- while (pivots != NULL && *npiv > 0) {
- if (pivots[*npiv - 1] > kth) {
- /* pivot larger than kth set it as upper bound */
- high = pivots[*npiv - 1] - 1;
- break;
- }
- else if (pivots[*npiv - 1] == kth) {
- /* kth was already found in a previous iteration -> done */
- return 0;
- }
-
- low = pivots[*npiv - 1] + 1;
-
- /* pop from stack */
- *npiv -= 1;
- }
-
- /*
- * use a faster O(n*kth) algorithm for very small kth
- * e.g. for interpolating percentile
- */
- if (kth - low < 3) {
- DUMBSELECT(v, tosort, low, high - low + 1, kth - low);
- store_pivot(kth, kth, pivots, npiv);
- return 0;
- }
- // Parenthesis around @inexact@ tells clang dead code as intentional
- else if ((@inexact@) && kth == num - 1) {
- /* useful to check if NaN present via partition(d, (x, -1)) */
- npy_intp k;
- npy_intp maxidx = low;
- @type@ maxval = v[IDX(low)];
- for (k = low + 1; k < num; k++) {
- if (!@TYPE@_LT(v[IDX(k)], maxval)) {
- maxidx = k;
- maxval = v[IDX(k)];
- }
- }
- SWAP(SORTEE(kth), SORTEE(maxidx));
- return 0;
- }
-
- depth_limit = npy_get_msb(num) * 2;
-
- /* guarantee three elements */
- for (;low + 1 < high;) {
- npy_intp ll = low + 1;
- npy_intp hh = high;
-
- /*
- * if we aren't making sufficient progress with median of 3
- * fall back to median-of-median5 pivot for linear worst case
- * med3 for small sizes is required to do unguarded partition
- */
- if (depth_limit > 0 || hh - ll < 5) {
- const npy_intp mid = low + (high - low) / 2;
- /* median of 3 pivot strategy,
- * swapping for efficient partition */
- MEDIAN3_SWAP(v, tosort, low, mid, high);
- }
- else {
- npy_intp mid;
- /* FIXME: always use pivots to optimize this iterative partition */
-#if @arg@
- mid = ll + amedian_of_median5_@suff@(v, tosort + ll, hh - ll, NULL, NULL);
-#else
- mid = ll + median_of_median5_@suff@(v + ll, hh - ll, NULL, NULL);
-#endif
- SWAP(SORTEE(mid), SORTEE(low));
- /* adapt for the larger partition than med3 pivot */
- ll--;
- hh++;
- }
-
- depth_limit--;
-
- /*
- * find place to put pivot (in low):
- * previous swapping removes need for bound checks
- * pivot 3-lowest [x x x] 3-highest
- */
- UNGUARDED_PARTITION(v, tosort, v[IDX(low)], &ll, &hh);
-
- /* move pivot into position */
- SWAP(SORTEE(low), SORTEE(hh));
-
- /* kth pivot stored later */
- if (hh != kth) {
- store_pivot(hh, kth, pivots, npiv);
- }
-
- if (hh >= kth)
- high = hh - 1;
- if (hh <= kth)
- low = ll;
- }
-
- /* two elements */
- if (high == low + 1) {
- if (@TYPE@_LT(v[IDX(high)], v[IDX(low)])) {
- SWAP(SORTEE(high), SORTEE(low))
- }
- }
- store_pivot(kth, kth, pivots, npiv);
-
- return 0;
-}
-
-
-#undef IDX
-#undef SWAP
-#undef SORTEE
-#undef MEDIAN3_SWAP
-#undef MEDIAN5
-#undef UNGUARDED_PARTITION
-#undef INTROSELECT
-#undef DUMBSELECT
-/**end repeat1**/
-
-/**end repeat**/
diff --git a/numpy/core/src/npysort/selection.cpp b/numpy/core/src/npysort/selection.cpp
new file mode 100644
index 000000000..8eb4a57aa
--- /dev/null
+++ b/numpy/core/src/npysort/selection.cpp
@@ -0,0 +1,645 @@
+/* -*- c -*- */
+
+/*
+ *
+ * The code is loosely based on the quickselect from
+ * Nicolas Devillard - 1998 public domain
+ * http://ndevilla.free.fr/median/median/
+ *
+ * Quick select with median of 3 pivot is usually the fastest,
+ * but the worst case scenario can be quadratic complexity,
+ * e.g. np.roll(np.arange(x), x / 2)
+ * To avoid this if it recurses too much it falls back to the
+ * worst case linear median of median of group 5 pivot strategy.
+ */
+
+#define NPY_NO_DEPRECATED_API NPY_API_VERSION
+
+#include "numpy/npy_math.h"
+
+#include "npy_partition.h"
+#include "npy_sort.h"
+#include "npysort_common.h"
+#include "numpy_tag.h"
+
+#include <cstdlib>
+#include <utility>
+
+#define NOT_USED NPY_UNUSED(unused)
+
+template <typename Tag, bool arg, typename type>
+NPY_NO_EXPORT int
+introselect_(type *v, npy_intp *tosort, npy_intp num, npy_intp kth,
+ npy_intp *pivots, npy_intp *npiv);
+
+/*
+ *****************************************************************************
+ ** NUMERIC SORTS **
+ *****************************************************************************
+ */
+
+static NPY_INLINE void
+store_pivot(npy_intp pivot, npy_intp kth, npy_intp *pivots, npy_intp *npiv)
+{
+ if (pivots == NULL) {
+ return;
+ }
+
+ /*
+ * If pivot is the requested kth store it, overwriting other pivots if
+ * required. This must be done so iterative partition can work without
+ * manually shifting lower data offset by kth each time
+ */
+ if (pivot == kth && *npiv == NPY_MAX_PIVOT_STACK) {
+ pivots[*npiv - 1] = pivot;
+ }
+ /*
+ * we only need pivots larger than current kth, larger pivots are not
+ * useful as partitions on smaller kth would reorder the stored pivots
+ */
+ else if (pivot >= kth && *npiv < NPY_MAX_PIVOT_STACK) {
+ pivots[*npiv] = pivot;
+ (*npiv) += 1;
+ }
+}
+
+template <typename type, bool arg>
+struct Sortee {
+ type *v;
+ Sortee(type *v, npy_intp *) : v(v) {}
+ type &operator()(npy_intp i) const { return v[i]; }
+};
+
+template <bool arg>
+struct Idx {
+ Idx(npy_intp *) {}
+ npy_intp operator()(npy_intp i) const { return i; }
+};
+
+template <typename type>
+struct Sortee<type, true> {
+ npy_intp *tosort;
+ Sortee(type *, npy_intp *tosort) : tosort(tosort) {}
+ npy_intp &operator()(npy_intp i) const { return tosort[i]; }
+};
+
+template <>
+struct Idx<true> {
+ npy_intp *tosort;
+ Idx(npy_intp *tosort) : tosort(tosort) {}
+ npy_intp operator()(npy_intp i) const { return tosort[i]; }
+};
+
+template <class T>
+static constexpr bool
+inexact()
+{
+ return !std::is_integral<T>::value;
+}
+
+/*
+ * median of 3 pivot strategy
+ * gets min and median and moves median to low and min to low + 1
+ * for efficient partitioning, see unguarded_partition
+ */
+template <typename Tag, bool arg, typename type>
+static NPY_INLINE void
+median3_swap_(type *v, npy_intp *tosort, npy_intp low, npy_intp mid,
+ npy_intp high)
+{
+ Idx<arg> idx(tosort);
+ Sortee<type, arg> sortee(v, tosort);
+
+ if (Tag::less(v[idx(high)], v[idx(mid)]))
+ std::swap(sortee(high), sortee(mid));
+ if (Tag::less(v[idx(high)], v[idx(low)]))
+ std::swap(sortee(high), sortee(low));
+ /* move pivot to low */
+ if (Tag::less(v[idx(low)], v[idx(mid)]))
+ std::swap(sortee(low), sortee(mid));
+ /* move 3-lowest element to low + 1 */
+ std::swap(sortee(mid), sortee(low + 1));
+}
+
+/* select index of median of five elements */
+template <typename Tag, bool arg, typename type>
+static npy_intp
+median5_(type *v, npy_intp *tosort)
+{
+ Idx<arg> idx(tosort);
+ Sortee<type, arg> sortee(v, tosort);
+
+ /* could be optimized as we only need the index (no swaps) */
+ if (Tag::less(v[idx(1)], v[idx(0)])) {
+ std::swap(sortee(1), sortee(0));
+ }
+ if (Tag::less(v[idx(4)], v[idx(3)])) {
+ std::swap(sortee(4), sortee(3));
+ }
+ if (Tag::less(v[idx(3)], v[idx(0)])) {
+ std::swap(sortee(3), sortee(0));
+ }
+ if (Tag::less(v[idx(4)], v[idx(1)])) {
+ std::swap(sortee(4), sortee(1));
+ }
+ if (Tag::less(v[idx(2)], v[idx(1)])) {
+ std::swap(sortee(2), sortee(1));
+ }
+ if (Tag::less(v[idx(3)], v[idx(2)])) {
+ if (Tag::less(v[idx(3)], v[idx(1)])) {
+ return 1;
+ }
+ else {
+ return 3;
+ }
+ }
+ else {
+ /* v[1] and v[2] swapped into order above */
+ return 2;
+ }
+}
+
+/*
+ * partition and return the index were the pivot belongs
+ * the data must have following property to avoid bound checks:
+ * ll ... hh
+ * lower-than-pivot [x x x x] larger-than-pivot
+ */
+template <typename Tag, bool arg, typename type>
+static NPY_INLINE void
+unguarded_partition_(type *v, npy_intp *tosort, const type pivot, npy_intp *ll,
+ npy_intp *hh)
+{
+ Idx<arg> idx(tosort);
+ Sortee<type, arg> sortee(v, tosort);
+
+ for (;;) {
+ do (*ll)++;
+ while (Tag::less(v[idx(*ll)], pivot));
+ do (*hh)--;
+ while (Tag::less(pivot, v[idx(*hh)]));
+
+ if (*hh < *ll)
+ break;
+
+ std::swap(sortee(*ll), sortee(*hh));
+ }
+}
+
+/*
+ * select median of median of blocks of 5
+ * if used as partition pivot it splits the range into at least 30%/70%
+ * allowing linear time worstcase quickselect
+ */
+template <typename Tag, bool arg, typename type>
+static npy_intp
+median_of_median5_(type *v, npy_intp *tosort, const npy_intp num,
+ npy_intp *pivots, npy_intp *npiv)
+{
+ Idx<arg> idx(tosort);
+ Sortee<type, arg> sortee(v, tosort);
+
+ npy_intp i, subleft;
+ npy_intp right = num - 1;
+ npy_intp nmed = (right + 1) / 5;
+ for (i = 0, subleft = 0; i < nmed; i++, subleft += 5) {
+ npy_intp m = median5_<Tag, arg>(v + (arg ? 0 : subleft),
+ tosort + (arg ? subleft : 0));
+ std::swap(sortee(subleft + m), sortee(i));
+ }
+
+ if (nmed > 2)
+ introselect_<Tag, arg>(v, tosort, nmed, nmed / 2, pivots, npiv);
+ return nmed / 2;
+}
+
+/*
+ * N^2 selection, fast only for very small kth
+ * useful for close multiple partitions
+ * (e.g. even element median, interpolating percentile)
+ */
+template <typename Tag, bool arg, typename type>
+static int
+dumb_select_(type *v, npy_intp *tosort, npy_intp num, npy_intp kth)
+{
+ Idx<arg> idx(tosort);
+ Sortee<type, arg> sortee(v, tosort);
+
+ npy_intp i;
+ for (i = 0; i <= kth; i++) {
+ npy_intp minidx = i;
+ type minval = v[idx(i)];
+ npy_intp k;
+ for (k = i + 1; k < num; k++) {
+ if (Tag::less(v[idx(k)], minval)) {
+ minidx = k;
+ minval = v[idx(k)];
+ }
+ }
+ std::swap(sortee(i), sortee(minidx));
+ }
+
+ return 0;
+}
+
+/*
+ * iterative median of 3 quickselect with cutoff to median-of-medians-of5
+ * receives stack of already computed pivots in v to minimize the
+ * partition size were kth is searched in
+ *
+ * area that needs partitioning in [...]
+ * kth 0: [8 7 6 5 4 3 2 1 0] -> med3 partitions elements [4, 2, 0]
+ * 0 1 2 3 4 8 7 5 6 -> pop requested kth -> stack [4, 2]
+ * kth 3: 0 1 2 [3] 4 8 7 5 6 -> stack [4]
+ * kth 5: 0 1 2 3 4 [8 7 5 6] -> stack [6]
+ * kth 8: 0 1 2 3 4 5 6 [8 7] -> stack []
+ *
+ */
+template <typename Tag, bool arg, typename type>
+NPY_NO_EXPORT int
+introselect_(type *v, npy_intp *tosort, npy_intp num, npy_intp kth,
+ npy_intp *pivots, npy_intp *npiv)
+{
+ Idx<arg> idx(tosort);
+ Sortee<type, arg> sortee(v, tosort);
+
+ npy_intp low = 0;
+ npy_intp high = num - 1;
+ int depth_limit;
+
+ if (npiv == NULL)
+ pivots = NULL;
+
+ while (pivots != NULL && *npiv > 0) {
+ if (pivots[*npiv - 1] > kth) {
+ /* pivot larger than kth set it as upper bound */
+ high = pivots[*npiv - 1] - 1;
+ break;
+ }
+ else if (pivots[*npiv - 1] == kth) {
+ /* kth was already found in a previous iteration -> done */
+ return 0;
+ }
+
+ low = pivots[*npiv - 1] + 1;
+
+ /* pop from stack */
+ *npiv -= 1;
+ }
+
+ /*
+ * use a faster O(n*kth) algorithm for very small kth
+ * e.g. for interpolating percentile
+ */
+ if (kth - low < 3) {
+ dumb_select_<Tag, arg>(v + (arg ? 0 : low), tosort + (arg ? low : 0),
+ high - low + 1, kth - low);
+ store_pivot(kth, kth, pivots, npiv);
+ return 0;
+ }
+
+ else if (inexact<type>() && kth == num - 1) {
+ /* useful to check if NaN present via partition(d, (x, -1)) */
+ npy_intp k;
+ npy_intp maxidx = low;
+ type maxval = v[idx(low)];
+ for (k = low + 1; k < num; k++) {
+ if (!Tag::less(v[idx(k)], maxval)) {
+ maxidx = k;
+ maxval = v[idx(k)];
+ }
+ }
+ std::swap(sortee(kth), sortee(maxidx));
+ return 0;
+ }
+
+ depth_limit = npy_get_msb(num) * 2;
+
+ /* guarantee three elements */
+ for (; low + 1 < high;) {
+ npy_intp ll = low + 1;
+ npy_intp hh = high;
+
+ /*
+ * if we aren't making sufficient progress with median of 3
+ * fall back to median-of-median5 pivot for linear worst case
+ * med3 for small sizes is required to do unguarded partition
+ */
+ if (depth_limit > 0 || hh - ll < 5) {
+ const npy_intp mid = low + (high - low) / 2;
+ /* median of 3 pivot strategy,
+ * swapping for efficient partition */
+ median3_swap_<Tag, arg>(v, tosort, low, mid, high);
+ }
+ else {
+ npy_intp mid;
+ /* FIXME: always use pivots to optimize this iterative partition */
+ mid = ll + median_of_median5_<Tag, arg>(v + (arg ? 0 : ll),
+ tosort + (arg ? ll : 0),
+ hh - ll, NULL, NULL);
+ std::swap(sortee(mid), sortee(low));
+ /* adapt for the larger partition than med3 pivot */
+ ll--;
+ hh++;
+ }
+
+ depth_limit--;
+
+ /*
+ * find place to put pivot (in low):
+ * previous swapping removes need for bound checks
+ * pivot 3-lowest [x x x] 3-highest
+ */
+ unguarded_partition_<Tag, arg>(v, tosort, v[idx(low)], &ll, &hh);
+
+ /* move pivot into position */
+ std::swap(sortee(low), sortee(hh));
+
+ /* kth pivot stored later */
+ if (hh != kth) {
+ store_pivot(hh, kth, pivots, npiv);
+ }
+
+ if (hh >= kth)
+ high = hh - 1;
+ if (hh <= kth)
+ low = ll;
+ }
+
+ /* two elements */
+ if (high == low + 1) {
+ if (Tag::less(v[idx(high)], v[idx(low)])) {
+ std::swap(sortee(high), sortee(low));
+ }
+ }
+ store_pivot(kth, kth, pivots, npiv);
+
+ return 0;
+}
+
+/***************************************
+ * C > C++ dispatch
+ ***************************************/
+
+extern "C" {
+NPY_NO_EXPORT int
+introselect_bool(npy_bool *v, npy_intp num, npy_intp kth, npy_intp *pivots,
+ npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::bool_tag, false>(v, nullptr, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+introselect_byte(npy_byte *v, npy_intp num, npy_intp kth, npy_intp *pivots,
+ npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::byte_tag, false>(v, nullptr, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+introselect_ubyte(npy_ubyte *v, npy_intp num, npy_intp kth, npy_intp *pivots,
+ npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::ubyte_tag, false>(v, nullptr, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+introselect_short(npy_short *v, npy_intp num, npy_intp kth, npy_intp *pivots,
+ npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::short_tag, false>(v, nullptr, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+introselect_ushort(npy_ushort *v, npy_intp num, npy_intp kth, npy_intp *pivots,
+ npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::ushort_tag, false>(v, nullptr, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+introselect_int(npy_int *v, npy_intp num, npy_intp kth, npy_intp *pivots,
+ npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::int_tag, false>(v, nullptr, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+introselect_uint(npy_uint *v, npy_intp num, npy_intp kth, npy_intp *pivots,
+ npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::uint_tag, false>(v, nullptr, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+introselect_long(npy_long *v, npy_intp num, npy_intp kth, npy_intp *pivots,
+ npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::long_tag, false>(v, nullptr, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+introselect_ulong(npy_ulong *v, npy_intp num, npy_intp kth, npy_intp *pivots,
+ npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::ulong_tag, false>(v, nullptr, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+introselect_longlong(npy_longlong *v, npy_intp num, npy_intp kth,
+ npy_intp *pivots, npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::longlong_tag, false>(v, nullptr, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+introselect_ulonglong(npy_ulonglong *v, npy_intp num, npy_intp kth,
+ npy_intp *pivots, npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::ulonglong_tag, false>(v, nullptr, num, kth,
+ pivots, npiv);
+}
+NPY_NO_EXPORT int
+introselect_half(npy_half *v, npy_intp num, npy_intp kth, npy_intp *pivots,
+ npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::half_tag, false>(v, nullptr, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+introselect_float(npy_float *v, npy_intp num, npy_intp kth, npy_intp *pivots,
+ npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::float_tag, false>(v, nullptr, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+introselect_double(npy_double *v, npy_intp num, npy_intp kth, npy_intp *pivots,
+ npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::double_tag, false>(v, nullptr, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+introselect_longdouble(npy_longdouble *v, npy_intp num, npy_intp kth,
+ npy_intp *pivots, npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::longdouble_tag, false>(v, nullptr, num, kth,
+ pivots, npiv);
+}
+NPY_NO_EXPORT int
+introselect_cfloat(npy_cfloat *v, npy_intp num, npy_intp kth, npy_intp *pivots,
+ npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::cfloat_tag, false>(v, nullptr, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+introselect_cdouble(npy_cdouble *v, npy_intp num, npy_intp kth,
+ npy_intp *pivots, npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::cdouble_tag, false>(v, nullptr, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+introselect_clongdouble(npy_clongdouble *v, npy_intp num, npy_intp kth,
+ npy_intp *pivots, npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::clongdouble_tag, false>(v, nullptr, num, kth,
+ pivots, npiv);
+}
+
+NPY_NO_EXPORT int
+aintroselect_bool(npy_bool *v, npy_intp *tosort, npy_intp num, npy_intp kth,
+ npy_intp *pivots, npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::bool_tag, true>(v, tosort, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+aintroselect_byte(npy_byte *v, npy_intp *tosort, npy_intp num, npy_intp kth,
+ npy_intp *pivots, npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::byte_tag, true>(v, tosort, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+aintroselect_ubyte(npy_ubyte *v, npy_intp *tosort, npy_intp num, npy_intp kth,
+ npy_intp *pivots, npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::ubyte_tag, true>(v, tosort, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+aintroselect_short(npy_short *v, npy_intp *tosort, npy_intp num, npy_intp kth,
+ npy_intp *pivots, npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::short_tag, true>(v, tosort, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+aintroselect_ushort(npy_ushort *v, npy_intp *tosort, npy_intp num,
+ npy_intp kth, npy_intp *pivots, npy_intp *npiv,
+ void *NOT_USED)
+{
+ return introselect_<npy::ushort_tag, true>(v, tosort, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+aintroselect_int(npy_int *v, npy_intp *tosort, npy_intp num, npy_intp kth,
+ npy_intp *pivots, npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::int_tag, true>(v, tosort, num, kth, pivots, npiv);
+}
+NPY_NO_EXPORT int
+aintroselect_uint(npy_uint *v, npy_intp *tosort, npy_intp num, npy_intp kth,
+ npy_intp *pivots, npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::uint_tag, true>(v, tosort, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+aintroselect_long(npy_long *v, npy_intp *tosort, npy_intp num, npy_intp kth,
+ npy_intp *pivots, npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::long_tag, true>(v, tosort, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+aintroselect_ulong(npy_ulong *v, npy_intp *tosort, npy_intp num, npy_intp kth,
+ npy_intp *pivots, npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::ulong_tag, true>(v, tosort, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+aintroselect_longlong(npy_longlong *v, npy_intp *tosort, npy_intp num,
+ npy_intp kth, npy_intp *pivots, npy_intp *npiv,
+ void *NOT_USED)
+{
+ return introselect_<npy::longlong_tag, true>(v, tosort, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+aintroselect_ulonglong(npy_ulonglong *v, npy_intp *tosort, npy_intp num,
+ npy_intp kth, npy_intp *pivots, npy_intp *npiv,
+ void *NOT_USED)
+{
+ return introselect_<npy::ulonglong_tag, true>(v, tosort, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+aintroselect_half(npy_half *v, npy_intp *tosort, npy_intp num, npy_intp kth,
+ npy_intp *pivots, npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::half_tag, true>(v, tosort, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+aintroselect_float(npy_float *v, npy_intp *tosort, npy_intp num, npy_intp kth,
+ npy_intp *pivots, npy_intp *npiv, void *NOT_USED)
+{
+ return introselect_<npy::float_tag, true>(v, tosort, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+aintroselect_double(npy_double *v, npy_intp *tosort, npy_intp num,
+ npy_intp kth, npy_intp *pivots, npy_intp *npiv,
+ void *NOT_USED)
+{
+ return introselect_<npy::double_tag, true>(v, tosort, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+aintroselect_longdouble(npy_longdouble *v, npy_intp *tosort, npy_intp num,
+ npy_intp kth, npy_intp *pivots, npy_intp *npiv,
+ void *NOT_USED)
+{
+ return introselect_<npy::longdouble_tag, true>(v, tosort, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+aintroselect_cfloat(npy_cfloat *v, npy_intp *tosort, npy_intp num,
+ npy_intp kth, npy_intp *pivots, npy_intp *npiv,
+ void *NOT_USED)
+{
+ return introselect_<npy::cfloat_tag, true>(v, tosort, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+aintroselect_cdouble(npy_cdouble *v, npy_intp *tosort, npy_intp num,
+ npy_intp kth, npy_intp *pivots, npy_intp *npiv,
+ void *NOT_USED)
+{
+ return introselect_<npy::cdouble_tag, true>(v, tosort, num, kth, pivots,
+ npiv);
+}
+NPY_NO_EXPORT int
+aintroselect_clongdouble(npy_clongdouble *v, npy_intp *tosort, npy_intp num,
+ npy_intp kth, npy_intp *pivots, npy_intp *npiv,
+ void *NOT_USED)
+{
+ return introselect_<npy::clongdouble_tag, true>(v, tosort, num, kth,
+ pivots, npiv);
+}
+}
diff --git a/numpy/core/src/npysort/timsort.c.src b/numpy/core/src/npysort/timsort.cpp
index 5298f5a1d..8bcd90061 100644
--- a/numpy/core/src/npysort/timsort.c.src
+++ b/numpy/core/src/npysort/timsort.cpp
@@ -26,7 +26,6 @@
* The heap sort is included for completeness.
*/
-
/* For details of Timsort, refer to
* https://github.com/python/cpython/blob/3.7/Objects/listsort.txt
*/
@@ -35,14 +34,16 @@
#include "npy_sort.h"
#include "npysort_common.h"
-#include <stdlib.h>
+#include "numpy_tag.h"
+
+#include <cstdlib>
+#include <utility>
/* enough for 32 * 1.618 ** 128 elements */
#define TIMSORT_STACK_SIZE 128
-
-
-static npy_intp compute_min_run(npy_intp num)
+static npy_intp
+compute_min_run(npy_intp num)
{
npy_intp r = 0;
@@ -59,14 +60,12 @@ typedef struct {
npy_intp l; /* length */
} run;
-
/* buffer for argsort. Declared here to avoid multiple declarations. */
typedef struct {
npy_intp *pw;
npy_intp size;
} buffer_intp;
-
/* buffer method */
static NPY_INLINE int
resize_buffer_intp(buffer_intp *buffer, npy_intp new_size)
@@ -76,16 +75,19 @@ resize_buffer_intp(buffer_intp *buffer, npy_intp new_size)
}
if (NPY_UNLIKELY(buffer->pw == NULL)) {
- buffer->pw = malloc(new_size * sizeof(npy_intp));
- } else {
- buffer->pw = realloc(buffer->pw, new_size * sizeof(npy_intp));
+ buffer->pw = (npy_intp *)malloc(new_size * sizeof(npy_intp));
+ }
+ else {
+ buffer->pw =
+ (npy_intp *)realloc(buffer->pw, new_size * sizeof(npy_intp));
}
buffer->size = new_size;
if (NPY_UNLIKELY(buffer->pw == NULL)) {
return -NPY_ENOMEM;
- } else {
+ }
+ else {
return 0;
}
}
@@ -96,56 +98,44 @@ resize_buffer_intp(buffer_intp *buffer, npy_intp new_size)
*****************************************************************************
*/
-
-/**begin repeat
- *
- * #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG,
- * LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE,
- * CFLOAT, CDOUBLE, CLONGDOUBLE, DATETIME, TIMEDELTA#
- * #suff = bool, byte, ubyte, short, ushort, int, uint, long, ulong,
- * longlong, ulonglong, half, float, double, longdouble,
- * cfloat, cdouble, clongdouble, datetime, timedelta#
- * #type = npy_bool, npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int,
- * npy_uint, npy_long, npy_ulong, npy_longlong, npy_ulonglong,
- * npy_ushort, npy_float, npy_double, npy_longdouble, npy_cfloat,
- * npy_cdouble, npy_clongdouble, npy_datetime, npy_timedelta#
- */
-
-
-typedef struct {
- @type@ * pw;
+template <typename Tag>
+struct buffer_ {
+ typename Tag::type *pw;
npy_intp size;
-} buffer_@suff@;
-
+};
+template <typename Tag>
static NPY_INLINE int
-resize_buffer_@suff@(buffer_@suff@ *buffer, npy_intp new_size)
+resize_buffer_(buffer_<Tag> *buffer, npy_intp new_size)
{
+ using type = typename Tag::type;
if (new_size <= buffer->size) {
return 0;
}
if (NPY_UNLIKELY(buffer->pw == NULL)) {
- buffer->pw = malloc(new_size * sizeof(@type@));
- } else {
- buffer->pw = realloc(buffer->pw, new_size * sizeof(@type@));
+ buffer->pw = (type *)malloc(new_size * sizeof(type));
+ }
+ else {
+ buffer->pw = (type *)realloc(buffer->pw, new_size * sizeof(type));
}
buffer->size = new_size;
if (NPY_UNLIKELY(buffer->pw == NULL)) {
return -NPY_ENOMEM;
- } else {
+ }
+ else {
return 0;
}
}
-
+template <typename Tag, typename type>
static npy_intp
-count_run_@suff@(@type@ *arr, npy_intp l, npy_intp num, npy_intp minrun)
+count_run_(type *arr, npy_intp l, npy_intp num, npy_intp minrun)
{
npy_intp sz;
- @type@ vc, *pl, *pi, *pj, *pr;
+ type vc, *pl, *pi, *pj, *pr;
if (NPY_UNLIKELY(num - l == 1)) {
return 1;
@@ -154,15 +144,18 @@ count_run_@suff@(@type@ *arr, npy_intp l, npy_intp num, npy_intp minrun)
pl = arr + l;
/* (not strictly) ascending sequence */
- if (!@TYPE@_LT(*(pl + 1), *pl)) {
- for (pi = pl + 1; pi < arr + num - 1 && !@TYPE@_LT(*(pi + 1), *pi); ++pi) {
+ if (!Tag::less(*(pl + 1), *pl)) {
+ for (pi = pl + 1; pi < arr + num - 1 && !Tag::less(*(pi + 1), *pi);
+ ++pi) {
}
- } else { /* (strictly) descending sequence */
- for (pi = pl + 1; pi < arr + num - 1 && @TYPE@_LT(*(pi + 1), *pi); ++pi) {
+ }
+ else { /* (strictly) descending sequence */
+ for (pi = pl + 1; pi < arr + num - 1 && Tag::less(*(pi + 1), *pi);
+ ++pi) {
}
for (pj = pl, pr = pi; pj < pr; ++pj, --pr) {
- @TYPE@_SWAP(*pj, *pr);
+ std::swap(*pj, *pr);
}
}
@@ -172,7 +165,8 @@ count_run_@suff@(@type@ *arr, npy_intp l, npy_intp num, npy_intp minrun)
if (sz < minrun) {
if (l + minrun < num) {
sz = minrun;
- } else {
+ }
+ else {
sz = num - l;
}
@@ -183,7 +177,7 @@ count_run_@suff@(@type@ *arr, npy_intp l, npy_intp num, npy_intp minrun)
vc = *pi;
pj = pi;
- while (pl < pj && @TYPE@_LT(vc, *(pj - 1))) {
+ while (pl < pj && Tag::less(vc, *(pj - 1))) {
*pj = *(pj - 1);
--pj;
}
@@ -195,43 +189,42 @@ count_run_@suff@(@type@ *arr, npy_intp l, npy_intp num, npy_intp minrun)
return sz;
}
-
/* when the left part of the array (p1) is smaller, copy p1 to buffer
* and merge from left to right
*/
+template <typename Tag, typename type>
static void
-merge_left_@suff@(@type@ *p1, npy_intp l1, @type@ *p2, npy_intp l2,
- @type@ *p3)
+merge_left_(type *p1, npy_intp l1, type *p2, npy_intp l2, type *p3)
{
- @type@ *end = p2 + l2;
- memcpy(p3, p1, sizeof(@type@) * l1);
+ type *end = p2 + l2;
+ memcpy(p3, p1, sizeof(type) * l1);
/* first element must be in p2 otherwise skipped in the caller */
*p1++ = *p2++;
while (p1 < p2 && p2 < end) {
- if (@TYPE@_LT(*p2, *p3)) {
+ if (Tag::less(*p2, *p3)) {
*p1++ = *p2++;
- } else {
+ }
+ else {
*p1++ = *p3++;
}
}
if (p1 != p2) {
- memcpy(p1, p3, sizeof(@type@) * (p2 - p1));
+ memcpy(p1, p3, sizeof(type) * (p2 - p1));
}
}
-
/* when the right part of the array (p2) is smaller, copy p2 to buffer
* and merge from right to left
*/
+template <typename Tag, typename type>
static void
-merge_right_@suff@(@type@ *p1, npy_intp l1, @type@ *p2, npy_intp l2,
- @type@ *p3)
+merge_right_(type *p1, npy_intp l1, type *p2, npy_intp l2, type *p3)
{
npy_intp ofs;
- @type@ *start = p1 - 1;
- memcpy(p3, p2, sizeof(@type@) * l2);
+ type *start = p1 - 1;
+ memcpy(p3, p2, sizeof(type) * l2);
p1 += l1 - 1;
p2 += l2 - 1;
p3 += l2 - 1;
@@ -239,31 +232,32 @@ merge_right_@suff@(@type@ *p1, npy_intp l1, @type@ *p2, npy_intp l2,
*p2-- = *p1--;
while (p1 < p2 && start < p1) {
- if (@TYPE@_LT(*p3, *p1)) {
+ if (Tag::less(*p3, *p1)) {
*p2-- = *p1--;
- } else {
+ }
+ else {
*p2-- = *p3--;
}
}
if (p1 != p2) {
ofs = p2 - start;
- memcpy(start + 1, p3 - ofs + 1, sizeof(@type@) * ofs);
+ memcpy(start + 1, p3 - ofs + 1, sizeof(type) * ofs);
}
}
-
/* Note: the naming convention of gallop functions are different from that of
* CPython. For example, here gallop_right means gallop from left toward right,
* whereas in CPython gallop_right means gallop
* and find the right most element among equal elements
*/
+template <typename Tag, typename type>
static npy_intp
-gallop_right_@suff@(const @type@ *arr, const npy_intp size, const @type@ key)
+gallop_right_(const type *arr, const npy_intp size, const type key)
{
npy_intp last_ofs, ofs, m;
- if (@TYPE@_LT(key, arr[0])) {
+ if (Tag::less(key, arr[0])) {
return 0;
}
@@ -276,9 +270,10 @@ gallop_right_@suff@(const @type@ *arr, const npy_intp size, const @type@ key)
break;
}
- if (@TYPE@_LT(key, arr[ofs])) {
+ if (Tag::less(key, arr[ofs])) {
break;
- } else {
+ }
+ else {
last_ofs = ofs;
/* ofs = 1, 3, 7, 15... */
ofs = (ofs << 1) + 1;
@@ -289,9 +284,10 @@ gallop_right_@suff@(const @type@ *arr, const npy_intp size, const @type@ key)
while (last_ofs + 1 < ofs) {
m = last_ofs + ((ofs - last_ofs) >> 1);
- if (@TYPE@_LT(key, arr[m])) {
+ if (Tag::less(key, arr[m])) {
ofs = m;
- } else {
+ }
+ else {
last_ofs = m;
}
}
@@ -300,13 +296,13 @@ gallop_right_@suff@(const @type@ *arr, const npy_intp size, const @type@ key)
return ofs;
}
-
+template <typename Tag, typename type>
static npy_intp
-gallop_left_@suff@(const @type@ *arr, const npy_intp size, const @type@ key)
+gallop_left_(const type *arr, const npy_intp size, const type key)
{
npy_intp last_ofs, ofs, l, m, r;
- if (@TYPE@_LT(arr[size - 1], key)) {
+ if (Tag::less(arr[size - 1], key)) {
return size;
}
@@ -319,9 +315,10 @@ gallop_left_@suff@(const @type@ *arr, const npy_intp size, const @type@ key)
break;
}
- if (@TYPE@_LT(arr[size - ofs - 1], key)) {
+ if (Tag::less(arr[size - ofs - 1], key)) {
break;
- } else {
+ }
+ else {
last_ofs = ofs;
ofs = (ofs << 1) + 1;
}
@@ -334,9 +331,10 @@ gallop_left_@suff@(const @type@ *arr, const npy_intp size, const @type@ key)
while (l + 1 < r) {
m = l + ((r - l) >> 1);
- if (@TYPE@_LT(arr[m], key)) {
+ if (Tag::less(arr[m], key)) {
l = m;
- } else {
+ }
+ else {
r = m;
}
}
@@ -345,14 +343,13 @@ gallop_left_@suff@(const @type@ *arr, const npy_intp size, const @type@ key)
return r;
}
-
+template <typename Tag, typename type>
static int
-merge_at_@suff@(@type@ *arr, const run *stack, const npy_intp at,
- buffer_@suff@ *buffer)
+merge_at_(type *arr, const run *stack, const npy_intp at, buffer_<Tag> *buffer)
{
int ret;
npy_intp s1, l1, s2, l2, k;
- @type@ *p1, *p2;
+ type *p1, *p2;
s1 = stack[at].s;
l1 = stack[at].l;
s2 = stack[at + 1].s;
@@ -361,7 +358,7 @@ merge_at_@suff@(@type@ *arr, const run *stack, const npy_intp at,
* if try to comment this out for debugging purpose, remember
* in the merging process the first element is skipped
*/
- k = gallop_right_@suff@(arr + s1, l1, arr[s2]);
+ k = gallop_right_<Tag>(arr + s1, l1, arr[s2]);
if (l1 == k) {
/* already sorted */
@@ -372,29 +369,33 @@ merge_at_@suff@(@type@ *arr, const run *stack, const npy_intp at,
l1 -= k;
p2 = arr + s2;
/* arr[s2-1] belongs to arr[s2+l2] */
- l2 = gallop_left_@suff@(arr + s2, l2, arr[s2 - 1]);
+ l2 = gallop_left_<Tag>(arr + s2, l2, arr[s2 - 1]);
if (l2 < l1) {
- ret = resize_buffer_@suff@(buffer, l2);
+ ret = resize_buffer_<Tag>(buffer, l2);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
- merge_right_@suff@(p1, l1, p2, l2, buffer->pw);
- } else {
- ret = resize_buffer_@suff@(buffer, l1);
+ merge_right_<Tag>(p1, l1, p2, l2, buffer->pw);
+ }
+ else {
+ ret = resize_buffer_<Tag>(buffer, l1);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
- merge_left_@suff@(p1, l1, p2, l2, buffer->pw);
+ merge_left_<Tag>(p1, l1, p2, l2, buffer->pw);
}
return 0;
}
-
+template <typename Tag, typename type>
static int
-try_collapse_@suff@(@type@ *arr, run *stack, npy_intp *stack_ptr,
- buffer_@suff@ *buffer)
+try_collapse_(type *arr, run *stack, npy_intp *stack_ptr, buffer_<Tag> *buffer)
{
int ret;
npy_intp A, B, C, top;
@@ -405,33 +406,42 @@ try_collapse_@suff@(@type@ *arr, run *stack, npy_intp *stack_ptr,
C = stack[top - 1].l;
if ((2 < top && stack[top - 3].l <= B + C) ||
- (3 < top && stack[top - 4].l <= stack[top - 3].l + B)) {
+ (3 < top && stack[top - 4].l <= stack[top - 3].l + B)) {
A = stack[top - 3].l;
if (A <= C) {
- ret = merge_at_@suff@(arr, stack, top - 3, buffer);
+ ret = merge_at_<Tag>(arr, stack, top - 3, buffer);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 3].l += B;
stack[top - 2] = stack[top - 1];
--top;
- } else {
- ret = merge_at_@suff@(arr, stack, top - 2, buffer);
+ }
+ else {
+ ret = merge_at_<Tag>(arr, stack, top - 2, buffer);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 2].l += C;
--top;
}
- } else if (1 < top && B <= C) {
- ret = merge_at_@suff@(arr, stack, top - 2, buffer);
+ }
+ else if (1 < top && B <= C) {
+ ret = merge_at_<Tag>(arr, stack, top - 2, buffer);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 2].l += C;
--top;
- } else {
+ }
+ else {
break;
}
}
@@ -440,26 +450,32 @@ try_collapse_@suff@(@type@ *arr, run *stack, npy_intp *stack_ptr,
return 0;
}
+template <typename Tag, typename type>
static int
-force_collapse_@suff@(@type@ *arr, run *stack, npy_intp *stack_ptr,
- buffer_@suff@ *buffer)
+force_collapse_(type *arr, run *stack, npy_intp *stack_ptr,
+ buffer_<Tag> *buffer)
{
int ret;
npy_intp top = *stack_ptr;
while (2 < top) {
if (stack[top - 3].l <= stack[top - 1].l) {
- ret = merge_at_@suff@(arr, stack, top - 3, buffer);
+ ret = merge_at_<Tag>(arr, stack, top - 3, buffer);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 3].l += stack[top - 2].l;
stack[top - 2] = stack[top - 1];
--top;
- } else {
- ret = merge_at_@suff@(arr, stack, top - 2, buffer);
+ }
+ else {
+ ret = merge_at_<Tag>(arr, stack, top - 2, buffer);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 2].l += stack[top - 1].l;
--top;
@@ -467,21 +483,24 @@ force_collapse_@suff@(@type@ *arr, run *stack, npy_intp *stack_ptr,
}
if (1 < top) {
- ret = merge_at_@suff@(arr, stack, top - 2, buffer);
+ ret = merge_at_<Tag>(arr, stack, top - 2, buffer);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
}
return 0;
}
-
-NPY_NO_EXPORT int
-timsort_@suff@(void *start, npy_intp num, void *NPY_UNUSED(varr))
+template <typename Tag>
+static int
+timsort_(void *start, npy_intp num)
{
+ using type = typename Tag::type;
int ret;
npy_intp l, n, stack_ptr, minrun;
- buffer_@suff@ buffer;
+ buffer_<Tag> buffer;
run stack[TIMSORT_STACK_SIZE];
buffer.pw = NULL;
buffer.size = 0;
@@ -489,20 +508,24 @@ timsort_@suff@(void *start, npy_intp num, void *NPY_UNUSED(varr))
minrun = compute_min_run(num);
for (l = 0; l < num;) {
- n = count_run_@suff@(start, l, num, minrun);
+ n = count_run_<Tag>((type *)start, l, num, minrun);
stack[stack_ptr].s = l;
stack[stack_ptr].l = n;
++stack_ptr;
- ret = try_collapse_@suff@(start, stack, &stack_ptr, &buffer);
+ ret = try_collapse_<Tag>((type *)start, stack, &stack_ptr, &buffer);
- if (NPY_UNLIKELY(ret < 0)) { goto cleanup; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ goto cleanup;
+ }
l += n;
}
- ret = force_collapse_@suff@(start, stack, &stack_ptr, &buffer);
+ ret = force_collapse_<Tag>((type *)start, stack, &stack_ptr, &buffer);
- if (NPY_UNLIKELY(ret < 0)) { goto cleanup; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ goto cleanup;
+ }
ret = 0;
cleanup:
@@ -512,16 +535,15 @@ cleanup:
return ret;
}
-
/* argsort */
-
+template <typename Tag, typename type>
static npy_intp
-acount_run_@suff@(@type@ *arr, npy_intp *tosort, npy_intp l, npy_intp num,
- npy_intp minrun)
+acount_run_(type *arr, npy_intp *tosort, npy_intp l, npy_intp num,
+ npy_intp minrun)
{
npy_intp sz;
- @type@ vc;
+ type vc;
npy_intp vi;
npy_intp *pl, *pi, *pj, *pr;
@@ -532,17 +554,20 @@ acount_run_@suff@(@type@ *arr, npy_intp *tosort, npy_intp l, npy_intp num,
pl = tosort + l;
/* (not strictly) ascending sequence */
- if (!@TYPE@_LT(arr[*(pl + 1)], arr[*pl])) {
- for (pi = pl + 1; pi < tosort + num - 1
- && !@TYPE@_LT(arr[*(pi + 1)], arr[*pi]); ++pi) {
+ if (!Tag::less(arr[*(pl + 1)], arr[*pl])) {
+ for (pi = pl + 1;
+ pi < tosort + num - 1 && !Tag::less(arr[*(pi + 1)], arr[*pi]);
+ ++pi) {
}
- } else { /* (strictly) descending sequence */
- for (pi = pl + 1; pi < tosort + num - 1
- && @TYPE@_LT(arr[*(pi + 1)], arr[*pi]); ++pi) {
+ }
+ else { /* (strictly) descending sequence */
+ for (pi = pl + 1;
+ pi < tosort + num - 1 && Tag::less(arr[*(pi + 1)], arr[*pi]);
+ ++pi) {
}
for (pj = pl, pr = pi; pj < pr; ++pj, --pr) {
- INTP_SWAP(*pj, *pr);
+ std::swap(*pj, *pr);
}
}
@@ -552,7 +577,8 @@ acount_run_@suff@(@type@ *arr, npy_intp *tosort, npy_intp l, npy_intp num,
if (sz < minrun) {
if (l + minrun < num) {
sz = minrun;
- } else {
+ }
+ else {
sz = num - l;
}
@@ -564,7 +590,7 @@ acount_run_@suff@(@type@ *arr, npy_intp *tosort, npy_intp l, npy_intp num,
vc = arr[*pi];
pj = pi;
- while (pl < pj && @TYPE@_LT(vc, arr[*(pj - 1)])) {
+ while (pl < pj && Tag::less(vc, arr[*(pj - 1)])) {
*pj = *(pj - 1);
--pj;
}
@@ -576,14 +602,14 @@ acount_run_@suff@(@type@ *arr, npy_intp *tosort, npy_intp l, npy_intp num,
return sz;
}
-
+template <typename Tag, typename type>
static npy_intp
-agallop_right_@suff@(const @type@ *arr, const npy_intp *tosort,
- const npy_intp size, const @type@ key)
+agallop_right_(const type *arr, const npy_intp *tosort, const npy_intp size,
+ const type key)
{
npy_intp last_ofs, ofs, m;
- if (@TYPE@_LT(key, arr[tosort[0]])) {
+ if (Tag::less(key, arr[tosort[0]])) {
return 0;
}
@@ -596,9 +622,10 @@ agallop_right_@suff@(const @type@ *arr, const npy_intp *tosort,
break;
}
- if (@TYPE@_LT(key, arr[tosort[ofs]])) {
+ if (Tag::less(key, arr[tosort[ofs]])) {
break;
- } else {
+ }
+ else {
last_ofs = ofs;
/* ofs = 1, 3, 7, 15... */
ofs = (ofs << 1) + 1;
@@ -609,9 +636,10 @@ agallop_right_@suff@(const @type@ *arr, const npy_intp *tosort,
while (last_ofs + 1 < ofs) {
m = last_ofs + ((ofs - last_ofs) >> 1);
- if (@TYPE@_LT(key, arr[tosort[m]])) {
+ if (Tag::less(key, arr[tosort[m]])) {
ofs = m;
- } else {
+ }
+ else {
last_ofs = m;
}
}
@@ -620,15 +648,14 @@ agallop_right_@suff@(const @type@ *arr, const npy_intp *tosort,
return ofs;
}
-
-
+template <typename Tag, typename type>
static npy_intp
-agallop_left_@suff@(const @type@ *arr, const npy_intp *tosort,
- const npy_intp size, const @type@ key)
+agallop_left_(const type *arr, const npy_intp *tosort, const npy_intp size,
+ const type key)
{
npy_intp last_ofs, ofs, l, m, r;
- if (@TYPE@_LT(arr[tosort[size - 1]], key)) {
+ if (Tag::less(arr[tosort[size - 1]], key)) {
return size;
}
@@ -641,24 +668,27 @@ agallop_left_@suff@(const @type@ *arr, const npy_intp *tosort,
break;
}
- if (@TYPE@_LT(arr[tosort[size - ofs - 1]], key)) {
+ if (Tag::less(arr[tosort[size - ofs - 1]], key)) {
break;
- } else {
+ }
+ else {
last_ofs = ofs;
ofs = (ofs << 1) + 1;
}
}
- /* now that arr[tosort[size-ofs-1]] < key <= arr[tosort[size-last_ofs-1]] */
+ /* now that arr[tosort[size-ofs-1]] < key <= arr[tosort[size-last_ofs-1]]
+ */
l = size - ofs - 1;
r = size - last_ofs - 1;
while (l + 1 < r) {
m = l + ((r - l) >> 1);
- if (@TYPE@_LT(arr[tosort[m]], key)) {
+ if (Tag::less(arr[tosort[m]], key)) {
l = m;
- } else {
+ }
+ else {
r = m;
}
}
@@ -667,11 +697,10 @@ agallop_left_@suff@(const @type@ *arr, const npy_intp *tosort,
return r;
}
-
+template <typename Tag, typename type>
static void
-amerge_left_@suff@(@type@ *arr, npy_intp *p1, npy_intp l1, npy_intp *p2,
- npy_intp l2,
- npy_intp *p3)
+amerge_left_(type *arr, npy_intp *p1, npy_intp l1, npy_intp *p2, npy_intp l2,
+ npy_intp *p3)
{
npy_intp *end = p2 + l2;
memcpy(p3, p1, sizeof(npy_intp) * l1);
@@ -679,9 +708,10 @@ amerge_left_@suff@(@type@ *arr, npy_intp *p1, npy_intp l1, npy_intp *p2,
*p1++ = *p2++;
while (p1 < p2 && p2 < end) {
- if (@TYPE@_LT(arr[*p2], arr[*p3])) {
+ if (Tag::less(arr[*p2], arr[*p3])) {
*p1++ = *p2++;
- } else {
+ }
+ else {
*p1++ = *p3++;
}
}
@@ -691,11 +721,10 @@ amerge_left_@suff@(@type@ *arr, npy_intp *p1, npy_intp l1, npy_intp *p2,
}
}
-
+template <typename Tag, typename type>
static void
-amerge_right_@suff@(@type@ *arr, npy_intp* p1, npy_intp l1, npy_intp *p2,
- npy_intp l2,
- npy_intp *p3)
+amerge_right_(type *arr, npy_intp *p1, npy_intp l1, npy_intp *p2, npy_intp l2,
+ npy_intp *p3)
{
npy_intp ofs;
npy_intp *start = p1 - 1;
@@ -707,9 +736,10 @@ amerge_right_@suff@(@type@ *arr, npy_intp* p1, npy_intp l1, npy_intp *p2,
*p2-- = *p1--;
while (p1 < p2 && start < p1) {
- if (@TYPE@_LT(arr[*p3], arr[*p1])) {
+ if (Tag::less(arr[*p3], arr[*p1])) {
*p2-- = *p1--;
- } else {
+ }
+ else {
*p2-- = *p3--;
}
}
@@ -720,11 +750,10 @@ amerge_right_@suff@(@type@ *arr, npy_intp* p1, npy_intp l1, npy_intp *p2,
}
}
-
+template <typename Tag, typename type>
static int
-amerge_at_@suff@(@type@ *arr, npy_intp *tosort, const run *stack,
- const npy_intp at,
- buffer_intp *buffer)
+amerge_at_(type *arr, npy_intp *tosort, const run *stack, const npy_intp at,
+ buffer_intp *buffer)
{
int ret;
npy_intp s1, l1, s2, l2, k;
@@ -734,7 +763,7 @@ amerge_at_@suff@(@type@ *arr, npy_intp *tosort, const run *stack,
s2 = stack[at + 1].s;
l2 = stack[at + 1].l;
/* tosort[s2] belongs to tosort[s1+k] */
- k = agallop_right_@suff@(arr, tosort + s1, l1, arr[tosort[s2]]);
+ k = agallop_right_<Tag>(arr, tosort + s1, l1, arr[tosort[s2]]);
if (l1 == k) {
/* already sorted */
@@ -745,30 +774,34 @@ amerge_at_@suff@(@type@ *arr, npy_intp *tosort, const run *stack,
l1 -= k;
p2 = tosort + s2;
/* tosort[s2-1] belongs to tosort[s2+l2] */
- l2 = agallop_left_@suff@(arr, tosort + s2, l2, arr[tosort[s2 - 1]]);
+ l2 = agallop_left_<Tag>(arr, tosort + s2, l2, arr[tosort[s2 - 1]]);
if (l2 < l1) {
ret = resize_buffer_intp(buffer, l2);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
- amerge_right_@suff@(arr, p1, l1, p2, l2, buffer->pw);
- } else {
+ amerge_right_<Tag>(arr, p1, l1, p2, l2, buffer->pw);
+ }
+ else {
ret = resize_buffer_intp(buffer, l1);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
- amerge_left_@suff@(arr, p1, l1, p2, l2, buffer->pw);
+ amerge_left_<Tag>(arr, p1, l1, p2, l2, buffer->pw);
}
return 0;
}
-
+template <typename Tag, typename type>
static int
-atry_collapse_@suff@(@type@ *arr, npy_intp *tosort, run *stack,
- npy_intp *stack_ptr,
- buffer_intp *buffer)
+atry_collapse_(type *arr, npy_intp *tosort, run *stack, npy_intp *stack_ptr,
+ buffer_intp *buffer)
{
int ret;
npy_intp A, B, C, top;
@@ -779,33 +812,42 @@ atry_collapse_@suff@(@type@ *arr, npy_intp *tosort, run *stack,
C = stack[top - 1].l;
if ((2 < top && stack[top - 3].l <= B + C) ||
- (3 < top && stack[top - 4].l <= stack[top - 3].l + B)) {
+ (3 < top && stack[top - 4].l <= stack[top - 3].l + B)) {
A = stack[top - 3].l;
if (A <= C) {
- ret = amerge_at_@suff@(arr, tosort, stack, top - 3, buffer);
+ ret = amerge_at_<Tag>(arr, tosort, stack, top - 3, buffer);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 3].l += B;
stack[top - 2] = stack[top - 1];
--top;
- } else {
- ret = amerge_at_@suff@(arr, tosort, stack, top - 2, buffer);
+ }
+ else {
+ ret = amerge_at_<Tag>(arr, tosort, stack, top - 2, buffer);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 2].l += C;
--top;
}
- } else if (1 < top && B <= C) {
- ret = amerge_at_@suff@(arr, tosort, stack, top - 2, buffer);
+ }
+ else if (1 < top && B <= C) {
+ ret = amerge_at_<Tag>(arr, tosort, stack, top - 2, buffer);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 2].l += C;
--top;
- } else {
+ }
+ else {
break;
}
}
@@ -814,28 +856,32 @@ atry_collapse_@suff@(@type@ *arr, npy_intp *tosort, run *stack,
return 0;
}
-
+template <typename Tag, typename type>
static int
-aforce_collapse_@suff@(@type@ *arr, npy_intp *tosort, run *stack,
- npy_intp *stack_ptr,
- buffer_intp *buffer)
+aforce_collapse_(type *arr, npy_intp *tosort, run *stack, npy_intp *stack_ptr,
+ buffer_intp *buffer)
{
int ret;
npy_intp top = *stack_ptr;
while (2 < top) {
if (stack[top - 3].l <= stack[top - 1].l) {
- ret = amerge_at_@suff@(arr, tosort, stack, top - 3, buffer);
+ ret = amerge_at_<Tag>(arr, tosort, stack, top - 3, buffer);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 3].l += stack[top - 2].l;
stack[top - 2] = stack[top - 1];
--top;
- } else {
- ret = amerge_at_@suff@(arr, tosort, stack, top - 2, buffer);
+ }
+ else {
+ ret = amerge_at_<Tag>(arr, tosort, stack, top - 2, buffer);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 2].l += stack[top - 1].l;
--top;
@@ -843,19 +889,21 @@ aforce_collapse_@suff@(@type@ *arr, npy_intp *tosort, run *stack,
}
if (1 < top) {
- ret = amerge_at_@suff@(arr, tosort, stack, top - 2, buffer);
+ ret = amerge_at_<Tag>(arr, tosort, stack, top - 2, buffer);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
}
return 0;
}
-
-NPY_NO_EXPORT int
-atimsort_@suff@(void *v, npy_intp *tosort, npy_intp num,
- void *NPY_UNUSED(varr))
+template <typename Tag>
+static int
+atimsort_(void *v, npy_intp *tosort, npy_intp num)
{
+ using type = typename Tag::type;
int ret;
npy_intp l, n, stack_ptr, minrun;
buffer_intp buffer;
@@ -866,20 +914,25 @@ atimsort_@suff@(void *v, npy_intp *tosort, npy_intp num,
minrun = compute_min_run(num);
for (l = 0; l < num;) {
- n = acount_run_@suff@(v, tosort, l, num, minrun);
+ n = acount_run_<Tag>((type *)v, tosort, l, num, minrun);
stack[stack_ptr].s = l;
stack[stack_ptr].l = n;
++stack_ptr;
- ret = atry_collapse_@suff@(v, tosort, stack, &stack_ptr, &buffer);
+ ret = atry_collapse_<Tag>((type *)v, tosort, stack, &stack_ptr,
+ &buffer);
- if (NPY_UNLIKELY(ret < 0)) { goto cleanup; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ goto cleanup;
+ }
l += n;
}
- ret = aforce_collapse_@suff@(v, tosort, stack, &stack_ptr, &buffer);
+ ret = aforce_collapse_<Tag>((type *)v, tosort, stack, &stack_ptr, &buffer);
- if (NPY_UNLIKELY(ret < 0)) { goto cleanup; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ goto cleanup;
+ }
ret = 0;
cleanup:
@@ -891,18 +944,15 @@ cleanup:
return ret;
}
-/**end repeat**/
-
-
-
/* For string sorts and generic sort, element comparisons are very expensive,
- * and the time cost of insertion sort (involves N**2 comparison) clearly hurts.
- * Implementing binary insertion sort and probably gallop mode during merging process
- * can hopefully boost the performance. Here as a temporary workaround we use shorter
- * run length to reduce the cost of insertion sort.
+ * and the time cost of insertion sort (involves N**2 comparison) clearly
+ * hurts. Implementing binary insertion sort and probably gallop mode during
+ * merging process can hopefully boost the performance. Here as a temporary
+ * workaround we use shorter run length to reduce the cost of insertion sort.
*/
-static npy_intp compute_min_run_short(npy_intp num)
+static npy_intp
+compute_min_run_short(npy_intp num)
{
npy_intp r = 0;
@@ -920,51 +970,47 @@ static npy_intp compute_min_run_short(npy_intp num)
*****************************************************************************
*/
-
-/**begin repeat
- *
- * #TYPE = STRING, UNICODE#
- * #suff = string, unicode#
- * #type = npy_char, npy_ucs4#
- */
-
-
-typedef struct {
- @type@ * pw;
+template <typename Tag>
+struct string_buffer_ {
+ typename Tag::type *pw;
npy_intp size;
size_t len;
-} buffer_@suff@;
-
+};
+template <typename Tag>
static NPY_INLINE int
-resize_buffer_@suff@(buffer_@suff@ *buffer, npy_intp new_size)
+resize_buffer_(string_buffer_<Tag> *buffer, npy_intp new_size)
{
+ using type = typename Tag::type;
if (new_size <= buffer->size) {
return 0;
}
if (NPY_UNLIKELY(buffer->pw == NULL)) {
- buffer->pw = malloc(sizeof(@type@) * new_size * buffer->len);
- } else {
- buffer->pw = realloc(buffer->pw, sizeof(@type@) * new_size * buffer->len);
+ buffer->pw = (type *)malloc(sizeof(type) * new_size * buffer->len);
+ }
+ else {
+ buffer->pw = (type *)realloc(buffer->pw,
+ sizeof(type) * new_size * buffer->len);
}
buffer->size = new_size;
if (NPY_UNLIKELY(buffer->pw == NULL)) {
return -NPY_ENOMEM;
- } else {
+ }
+ else {
return 0;
}
}
-
+template <typename Tag, typename type>
static npy_intp
-count_run_@suff@(@type@ *arr, npy_intp l, npy_intp num, npy_intp minrun,
- @type@ *vp, size_t len)
+count_run_(type *arr, npy_intp l, npy_intp num, npy_intp minrun, type *vp,
+ size_t len)
{
npy_intp sz;
- @type@ *pl, *pi, *pj, *pr;
+ type *pl, *pi, *pj, *pr;
if (NPY_UNLIKELY(num - l == 1)) {
return 1;
@@ -973,17 +1019,20 @@ count_run_@suff@(@type@ *arr, npy_intp l, npy_intp num, npy_intp minrun,
pl = arr + l * len;
/* (not strictly) ascending sequence */
- if (!@TYPE@_LT(pl + len, pl, len)) {
- for (pi = pl + len; pi < arr + (num - 1) * len
- && !@TYPE@_LT(pi + len, pi, len); pi += len) {
+ if (!Tag::less(pl + len, pl, len)) {
+ for (pi = pl + len;
+ pi < arr + (num - 1) * len && !Tag::less(pi + len, pi, len);
+ pi += len) {
}
- } else { /* (strictly) descending sequence */
- for (pi = pl + len; pi < arr + (num - 1) * len
- && @TYPE@_LT(pi + len, pi, len); pi += len) {
+ }
+ else { /* (strictly) descending sequence */
+ for (pi = pl + len;
+ pi < arr + (num - 1) * len && Tag::less(pi + len, pi, len);
+ pi += len) {
}
for (pj = pl, pr = pi; pj < pr; pj += len, pr -= len) {
- @TYPE@_SWAP(pj, pr, len);
+ Tag::swap(pj, pr, len);
}
}
@@ -993,7 +1042,8 @@ count_run_@suff@(@type@ *arr, npy_intp l, npy_intp num, npy_intp minrun,
if (sz < minrun) {
if (l + minrun < num) {
sz = minrun;
- } else {
+ }
+ else {
sz = num - l;
}
@@ -1001,29 +1051,29 @@ count_run_@suff@(@type@ *arr, npy_intp l, npy_intp num, npy_intp minrun,
/* insertion sort */
for (; pi < pr; pi += len) {
- @TYPE@_COPY(vp, pi, len);
+ Tag::copy(vp, pi, len);
pj = pi;
- while (pl < pj && @TYPE@_LT(vp, pj - len, len)) {
- @TYPE@_COPY(pj, pj - len, len);
+ while (pl < pj && Tag::less(vp, pj - len, len)) {
+ Tag::copy(pj, pj - len, len);
pj -= len;
}
- @TYPE@_COPY(pj, vp, len);
+ Tag::copy(pj, vp, len);
}
}
return sz;
}
-
+template <typename Tag>
static npy_intp
-gallop_right_@suff@(const @type@ *arr, const npy_intp size,
- const @type@ *key, size_t len)
+gallop_right_(const typename Tag::type *arr, const npy_intp size,
+ const typename Tag::type *key, size_t len)
{
npy_intp last_ofs, ofs, m;
- if (@TYPE@_LT(key, arr, len)) {
+ if (Tag::less(key, arr, len)) {
return 0;
}
@@ -1036,9 +1086,10 @@ gallop_right_@suff@(const @type@ *arr, const npy_intp size,
break;
}
- if (@TYPE@_LT(key, arr + ofs * len, len)) {
+ if (Tag::less(key, arr + ofs * len, len)) {
break;
- } else {
+ }
+ else {
last_ofs = ofs;
/* ofs = 1, 3, 7, 15... */
ofs = (ofs << 1) + 1;
@@ -1049,9 +1100,10 @@ gallop_right_@suff@(const @type@ *arr, const npy_intp size,
while (last_ofs + 1 < ofs) {
m = last_ofs + ((ofs - last_ofs) >> 1);
- if (@TYPE@_LT(key, arr + m * len, len)) {
+ if (Tag::less(key, arr + m * len, len)) {
ofs = m;
- } else {
+ }
+ else {
last_ofs = m;
}
}
@@ -1060,15 +1112,14 @@ gallop_right_@suff@(const @type@ *arr, const npy_intp size,
return ofs;
}
-
-
+template <typename Tag>
static npy_intp
-gallop_left_@suff@(const @type@ *arr, const npy_intp size, const @type@ *key,
- size_t len)
+gallop_left_(const typename Tag::type *arr, const npy_intp size,
+ const typename Tag::type *key, size_t len)
{
npy_intp last_ofs, ofs, l, m, r;
- if (@TYPE@_LT(arr + (size - 1) * len, key, len)) {
+ if (Tag::less(arr + (size - 1) * len, key, len)) {
return size;
}
@@ -1081,9 +1132,10 @@ gallop_left_@suff@(const @type@ *arr, const npy_intp size, const @type@ *key,
break;
}
- if (@TYPE@_LT(arr + (size - ofs - 1) * len, key, len)) {
+ if (Tag::less(arr + (size - ofs - 1) * len, key, len)) {
break;
- } else {
+ }
+ else {
last_ofs = ofs;
ofs = (ofs << 1) + 1;
}
@@ -1096,9 +1148,10 @@ gallop_left_@suff@(const @type@ *arr, const npy_intp size, const @type@ *key,
while (l + 1 < r) {
m = l + ((r - l) >> 1);
- if (@TYPE@_LT(arr + m * len, key, len)) {
+ if (Tag::less(arr + m * len, key, len)) {
l = m;
- } else {
+ }
+ else {
r = m;
}
}
@@ -1107,58 +1160,61 @@ gallop_left_@suff@(const @type@ *arr, const npy_intp size, const @type@ *key,
return r;
}
-
+template <typename Tag>
static void
-merge_left_@suff@(@type@ *p1, npy_intp l1, @type@ *p2, npy_intp l2,
- @type@ *p3, size_t len)
+merge_left_(typename Tag::type *p1, npy_intp l1, typename Tag::type *p2,
+ npy_intp l2, typename Tag::type *p3, size_t len)
{
- @type@ *end = p2 + l2 * len;
- memcpy(p3, p1, sizeof(@type@) * l1 * len);
+ using type = typename Tag::type;
+ type *end = p2 + l2 * len;
+ memcpy(p3, p1, sizeof(type) * l1 * len);
/* first element must be in p2 otherwise skipped in the caller */
- @TYPE@_COPY(p1, p2, len);
+ Tag::copy(p1, p2, len);
p1 += len;
p2 += len;
while (p1 < p2 && p2 < end) {
- if (@TYPE@_LT(p2, p3, len)) {
- @TYPE@_COPY(p1, p2, len);
+ if (Tag::less(p2, p3, len)) {
+ Tag::copy(p1, p2, len);
p1 += len;
p2 += len;
- } else {
- @TYPE@_COPY(p1, p3, len);
+ }
+ else {
+ Tag::copy(p1, p3, len);
p1 += len;
p3 += len;
}
}
if (p1 != p2) {
- memcpy(p1, p3, sizeof(@type@) * (p2 - p1));
+ memcpy(p1, p3, sizeof(type) * (p2 - p1));
}
}
-
+template <typename Tag, typename type>
static void
-merge_right_@suff@(@type@ *p1, npy_intp l1, @type@ *p2, npy_intp l2,
- @type@ *p3, size_t len)
+merge_right_(type *p1, npy_intp l1, type *p2, npy_intp l2, type *p3,
+ size_t len)
{
npy_intp ofs;
- @type@ *start = p1 - len;
- memcpy(p3, p2, sizeof(@type@) * l2 * len);
+ type *start = p1 - len;
+ memcpy(p3, p2, sizeof(type) * l2 * len);
p1 += (l1 - 1) * len;
p2 += (l2 - 1) * len;
p3 += (l2 - 1) * len;
/* first element must be in p1 otherwise skipped in the caller */
- @TYPE@_COPY(p2, p1, len);
+ Tag::copy(p2, p1, len);
p2 -= len;
p1 -= len;
while (p1 < p2 && start < p1) {
- if (@TYPE@_LT(p3, p1, len)) {
- @TYPE@_COPY(p2, p1, len);
+ if (Tag::less(p3, p1, len)) {
+ Tag::copy(p2, p1, len);
p2 -= len;
p1 -= len;
- } else {
- @TYPE@_COPY(p2, p3, len);
+ }
+ else {
+ Tag::copy(p2, p3, len);
p2 -= len;
p3 -= len;
}
@@ -1166,25 +1222,25 @@ merge_right_@suff@(@type@ *p1, npy_intp l1, @type@ *p2, npy_intp l2,
if (p1 != p2) {
ofs = p2 - start;
- memcpy(start + len, p3 - ofs + len, sizeof(@type@) * ofs);
+ memcpy(start + len, p3 - ofs + len, sizeof(type) * ofs);
}
}
-
+template <typename Tag, typename type>
static int
-merge_at_@suff@(@type@ *arr, const run *stack, const npy_intp at,
- buffer_@suff@ *buffer, size_t len)
+merge_at_(type *arr, const run *stack, const npy_intp at,
+ string_buffer_<Tag> *buffer, size_t len)
{
int ret;
npy_intp s1, l1, s2, l2, k;
- @type@ *p1, *p2;
+ type *p1, *p2;
s1 = stack[at].s;
l1 = stack[at].l;
s2 = stack[at + 1].s;
l2 = stack[at + 1].l;
/* arr[s2] belongs to arr[s1+k] */
- @TYPE@_COPY(buffer->pw, arr + s2 * len, len);
- k = gallop_right_@suff@(arr + s1 * len, l1, buffer->pw, len);
+ Tag::copy(buffer->pw, arr + s2 * len, len);
+ k = gallop_right_<Tag>(arr + s1 * len, l1, buffer->pw, len);
if (l1 == k) {
/* already sorted */
@@ -1195,30 +1251,35 @@ merge_at_@suff@(@type@ *arr, const run *stack, const npy_intp at,
l1 -= k;
p2 = arr + s2 * len;
/* arr[s2-1] belongs to arr[s2+l2] */
- @TYPE@_COPY(buffer->pw, arr + (s2 - 1) * len, len);
- l2 = gallop_left_@suff@(arr + s2 * len, l2, buffer->pw, len);
+ Tag::copy(buffer->pw, arr + (s2 - 1) * len, len);
+ l2 = gallop_left_<Tag>(arr + s2 * len, l2, buffer->pw, len);
if (l2 < l1) {
- ret = resize_buffer_@suff@(buffer, l2);
+ ret = resize_buffer_<Tag>(buffer, l2);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
- merge_right_@suff@(p1, l1, p2, l2, buffer->pw, len);
- } else {
- ret = resize_buffer_@suff@(buffer, l1);
+ merge_right_<Tag>(p1, l1, p2, l2, buffer->pw, len);
+ }
+ else {
+ ret = resize_buffer_<Tag>(buffer, l1);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
- merge_left_@suff@(p1, l1, p2, l2, buffer->pw, len);
+ merge_left_<Tag>(p1, l1, p2, l2, buffer->pw, len);
}
return 0;
}
-
+template <typename Tag, typename type>
static int
-try_collapse_@suff@(@type@ *arr, run *stack, npy_intp *stack_ptr,
- buffer_@suff@ *buffer, size_t len)
+try_collapse_(type *arr, run *stack, npy_intp *stack_ptr,
+ string_buffer_<Tag> *buffer, size_t len)
{
int ret;
npy_intp A, B, C, top;
@@ -1229,33 +1290,42 @@ try_collapse_@suff@(@type@ *arr, run *stack, npy_intp *stack_ptr,
C = stack[top - 1].l;
if ((2 < top && stack[top - 3].l <= B + C) ||
- (3 < top && stack[top - 4].l <= stack[top - 3].l + B)) {
+ (3 < top && stack[top - 4].l <= stack[top - 3].l + B)) {
A = stack[top - 3].l;
if (A <= C) {
- ret = merge_at_@suff@(arr, stack, top - 3, buffer, len);
+ ret = merge_at_<Tag>(arr, stack, top - 3, buffer, len);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 3].l += B;
stack[top - 2] = stack[top - 1];
--top;
- } else {
- ret = merge_at_@suff@(arr, stack, top - 2, buffer, len);
+ }
+ else {
+ ret = merge_at_<Tag>(arr, stack, top - 2, buffer, len);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 2].l += C;
--top;
}
- } else if (1 < top && B <= C) {
- ret = merge_at_@suff@(arr, stack, top - 2, buffer, len);
+ }
+ else if (1 < top && B <= C) {
+ ret = merge_at_<Tag>(arr, stack, top - 2, buffer, len);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 2].l += C;
--top;
- } else {
+ }
+ else {
break;
}
}
@@ -1264,27 +1334,32 @@ try_collapse_@suff@(@type@ *arr, run *stack, npy_intp *stack_ptr,
return 0;
}
-
+template <typename Tag, typename type>
static int
-force_collapse_@suff@(@type@ *arr, run *stack, npy_intp *stack_ptr,
- buffer_@suff@ *buffer, size_t len)
+force_collapse_(type *arr, run *stack, npy_intp *stack_ptr,
+ string_buffer_<Tag> *buffer, size_t len)
{
int ret;
npy_intp top = *stack_ptr;
while (2 < top) {
if (stack[top - 3].l <= stack[top - 1].l) {
- ret = merge_at_@suff@(arr, stack, top - 3, buffer, len);
+ ret = merge_at_<Tag>(arr, stack, top - 3, buffer, len);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 3].l += stack[top - 2].l;
stack[top - 2] = stack[top - 1];
--top;
- } else {
- ret = merge_at_@suff@(arr, stack, top - 2, buffer, len);
+ }
+ else {
+ ret = merge_at_<Tag>(arr, stack, top - 2, buffer, len);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 2].l += stack[top - 1].l;
--top;
@@ -1292,25 +1367,28 @@ force_collapse_@suff@(@type@ *arr, run *stack, npy_intp *stack_ptr,
}
if (1 < top) {
- ret = merge_at_@suff@(arr, stack, top - 2, buffer, len);
+ ret = merge_at_<Tag>(arr, stack, top - 2, buffer, len);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
}
return 0;
}
-
+template <typename Tag>
NPY_NO_EXPORT int
-timsort_@suff@(void *start, npy_intp num, void *varr)
+string_timsort_(void *start, npy_intp num, void *varr)
{
- PyArrayObject *arr = varr;
+ using type = typename Tag::type;
+ PyArrayObject *arr = reinterpret_cast<PyArrayObject *>(varr);
size_t elsize = PyArray_ITEMSIZE(arr);
- size_t len = elsize / sizeof(@type@);
+ size_t len = elsize / sizeof(type);
int ret;
npy_intp l, n, stack_ptr, minrun;
run stack[TIMSORT_STACK_SIZE];
- buffer_@suff@ buffer;
+ string_buffer_<Tag> buffer;
/* Items that have zero size don't make sense to sort */
if (len == 0) {
@@ -1323,26 +1401,33 @@ timsort_@suff@(void *start, npy_intp num, void *varr)
stack_ptr = 0;
minrun = compute_min_run_short(num);
/* used for insertion sort and gallop key */
- ret = resize_buffer_@suff@(&buffer, 1);
+ ret = resize_buffer_<Tag>(&buffer, 1);
- if (NPY_UNLIKELY(ret < 0)) { goto cleanup; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ goto cleanup;
+ }
for (l = 0; l < num;) {
- n = count_run_@suff@(start, l, num, minrun, buffer.pw, len);
+ n = count_run_<Tag>((type *)start, l, num, minrun, buffer.pw, len);
/* both s and l are scaled by len */
stack[stack_ptr].s = l;
stack[stack_ptr].l = n;
++stack_ptr;
- ret = try_collapse_@suff@(start, stack, &stack_ptr, &buffer, len);
+ ret = try_collapse_<Tag>((type *)start, stack, &stack_ptr, &buffer,
+ len);
- if (NPY_UNLIKELY(ret < 0)) { goto cleanup; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ goto cleanup;
+ }
l += n;
}
- ret = force_collapse_@suff@(start, stack, &stack_ptr, &buffer, len);
+ ret = force_collapse_<Tag>((type *)start, stack, &stack_ptr, &buffer, len);
- if (NPY_UNLIKELY(ret < 0)) { goto cleanup; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ goto cleanup;
+ }
ret = 0;
@@ -1353,13 +1438,12 @@ cleanup:
return ret;
}
-
/* argsort */
-
+template <typename Tag, typename type>
static npy_intp
-acount_run_@suff@(@type@ *arr, npy_intp *tosort, npy_intp l, npy_intp num,
- npy_intp minrun, size_t len)
+acount_run_(type *arr, npy_intp *tosort, npy_intp l, npy_intp num,
+ npy_intp minrun, size_t len)
{
npy_intp sz;
npy_intp vi;
@@ -1372,17 +1456,22 @@ acount_run_@suff@(@type@ *arr, npy_intp *tosort, npy_intp l, npy_intp num,
pl = tosort + l;
/* (not strictly) ascending sequence */
- if (!@TYPE@_LT(arr + (*(pl + 1)) * len, arr + (*pl) * len, len)) {
- for (pi = pl + 1; pi < tosort + num - 1
- && !@TYPE@_LT(arr + (*(pi + 1)) * len, arr + (*pi) * len, len); ++pi) {
+ if (!Tag::less(arr + (*(pl + 1)) * len, arr + (*pl) * len, len)) {
+ for (pi = pl + 1;
+ pi < tosort + num - 1 &&
+ !Tag::less(arr + (*(pi + 1)) * len, arr + (*pi) * len, len);
+ ++pi) {
}
- } else { /* (strictly) descending sequence */
- for (pi = pl + 1; pi < tosort + num - 1
- && @TYPE@_LT(arr + (*(pi + 1)) * len, arr + (*pi) * len, len); ++pi) {
+ }
+ else { /* (strictly) descending sequence */
+ for (pi = pl + 1;
+ pi < tosort + num - 1 &&
+ Tag::less(arr + (*(pi + 1)) * len, arr + (*pi) * len, len);
+ ++pi) {
}
for (pj = pl, pr = pi; pj < pr; ++pj, --pr) {
- INTP_SWAP(*pj, *pr);
+ std::swap(*pj, *pr);
}
}
@@ -1392,7 +1481,8 @@ acount_run_@suff@(@type@ *arr, npy_intp *tosort, npy_intp l, npy_intp num,
if (sz < minrun) {
if (l + minrun < num) {
sz = minrun;
- } else {
+ }
+ else {
sz = num - l;
}
@@ -1403,7 +1493,8 @@ acount_run_@suff@(@type@ *arr, npy_intp *tosort, npy_intp l, npy_intp num,
vi = *pi;
pj = pi;
- while (pl < pj && @TYPE@_LT(arr + vi * len, arr + (*(pj - 1)) * len, len)) {
+ while (pl < pj &&
+ Tag::less(arr + vi * len, arr + (*(pj - 1)) * len, len)) {
*pj = *(pj - 1);
--pj;
}
@@ -1415,14 +1506,14 @@ acount_run_@suff@(@type@ *arr, npy_intp *tosort, npy_intp l, npy_intp num,
return sz;
}
-
+template <typename Tag, typename type>
static npy_intp
-agallop_left_@suff@(const @type@ *arr, const npy_intp *tosort,
- const npy_intp size, const @type@ *key, size_t len)
+agallop_left_(const type *arr, const npy_intp *tosort, const npy_intp size,
+ const type *key, size_t len)
{
npy_intp last_ofs, ofs, l, m, r;
- if (@TYPE@_LT(arr + tosort[size - 1] * len, key, len)) {
+ if (Tag::less(arr + tosort[size - 1] * len, key, len)) {
return size;
}
@@ -1435,24 +1526,27 @@ agallop_left_@suff@(const @type@ *arr, const npy_intp *tosort,
break;
}
- if (@TYPE@_LT(arr + tosort[size - ofs - 1] * len, key, len)) {
+ if (Tag::less(arr + tosort[size - ofs - 1] * len, key, len)) {
break;
- } else {
+ }
+ else {
last_ofs = ofs;
ofs = (ofs << 1) + 1;
}
}
- /* now that arr[tosort[size-ofs-1]*len] < key <= arr[tosort[size-last_ofs-1]*len] */
+ /* now that arr[tosort[size-ofs-1]*len] < key <=
+ * arr[tosort[size-last_ofs-1]*len] */
l = size - ofs - 1;
r = size - last_ofs - 1;
while (l + 1 < r) {
m = l + ((r - l) >> 1);
- if (@TYPE@_LT(arr + tosort[m] * len, key, len)) {
+ if (Tag::less(arr + tosort[m] * len, key, len)) {
l = m;
- } else {
+ }
+ else {
r = m;
}
}
@@ -1461,14 +1555,14 @@ agallop_left_@suff@(const @type@ *arr, const npy_intp *tosort,
return r;
}
-
+template <typename Tag, typename type>
static npy_intp
-agallop_right_@suff@(const @type@ *arr, const npy_intp *tosort,
- const npy_intp size, const @type@ *key, size_t len)
+agallop_right_(const type *arr, const npy_intp *tosort, const npy_intp size,
+ const type *key, size_t len)
{
npy_intp last_ofs, ofs, m;
- if (@TYPE@_LT(key, arr + tosort[0] * len, len)) {
+ if (Tag::less(key, arr + tosort[0] * len, len)) {
return 0;
}
@@ -1481,9 +1575,10 @@ agallop_right_@suff@(const @type@ *arr, const npy_intp *tosort,
break;
}
- if (@TYPE@_LT(key, arr + tosort[ofs] * len, len)) {
+ if (Tag::less(key, arr + tosort[ofs] * len, len)) {
break;
- } else {
+ }
+ else {
last_ofs = ofs;
/* ofs = 1, 3, 7, 15... */
ofs = (ofs << 1) + 1;
@@ -1494,9 +1589,10 @@ agallop_right_@suff@(const @type@ *arr, const npy_intp *tosort,
while (last_ofs + 1 < ofs) {
m = last_ofs + ((ofs - last_ofs) >> 1);
- if (@TYPE@_LT(key, arr + tosort[m] * len, len)) {
+ if (Tag::less(key, arr + tosort[m] * len, len)) {
ofs = m;
- } else {
+ }
+ else {
last_ofs = m;
}
}
@@ -1505,11 +1601,10 @@ agallop_right_@suff@(const @type@ *arr, const npy_intp *tosort,
return ofs;
}
-
-
+template <typename Tag, typename type>
static void
-amerge_left_@suff@(@type@ *arr, npy_intp *p1, npy_intp l1, npy_intp *p2,
- npy_intp l2, npy_intp *p3, size_t len)
+amerge_left_(type *arr, npy_intp *p1, npy_intp l1, npy_intp *p2, npy_intp l2,
+ npy_intp *p3, size_t len)
{
npy_intp *end = p2 + l2;
memcpy(p3, p1, sizeof(npy_intp) * l1);
@@ -1517,9 +1612,10 @@ amerge_left_@suff@(@type@ *arr, npy_intp *p1, npy_intp l1, npy_intp *p2,
*p1++ = *p2++;
while (p1 < p2 && p2 < end) {
- if (@TYPE@_LT(arr + (*p2) * len, arr + (*p3) * len, len)) {
+ if (Tag::less(arr + (*p2) * len, arr + (*p3) * len, len)) {
*p1++ = *p2++;
- } else {
+ }
+ else {
*p1++ = *p3++;
}
}
@@ -1529,10 +1625,10 @@ amerge_left_@suff@(@type@ *arr, npy_intp *p1, npy_intp l1, npy_intp *p2,
}
}
-
+template <typename Tag, typename type>
static void
-amerge_right_@suff@(@type@ *arr, npy_intp* p1, npy_intp l1, npy_intp *p2,
- npy_intp l2, npy_intp *p3, size_t len)
+amerge_right_(type *arr, npy_intp *p1, npy_intp l1, npy_intp *p2, npy_intp l2,
+ npy_intp *p3, size_t len)
{
npy_intp ofs;
npy_intp *start = p1 - 1;
@@ -1544,9 +1640,10 @@ amerge_right_@suff@(@type@ *arr, npy_intp* p1, npy_intp l1, npy_intp *p2,
*p2-- = *p1--;
while (p1 < p2 && start < p1) {
- if (@TYPE@_LT(arr + (*p3) * len, arr + (*p1) * len, len)) {
+ if (Tag::less(arr + (*p3) * len, arr + (*p1) * len, len)) {
*p2-- = *p1--;
- } else {
+ }
+ else {
*p2-- = *p3--;
}
}
@@ -1557,11 +1654,10 @@ amerge_right_@suff@(@type@ *arr, npy_intp* p1, npy_intp l1, npy_intp *p2,
}
}
-
-
+template <typename Tag, typename type>
static int
-amerge_at_@suff@(@type@ *arr, npy_intp *tosort, const run *stack,
- const npy_intp at, buffer_intp *buffer, size_t len)
+amerge_at_(type *arr, npy_intp *tosort, const run *stack, const npy_intp at,
+ buffer_intp *buffer, size_t len)
{
int ret;
npy_intp s1, l1, s2, l2, k;
@@ -1571,7 +1667,7 @@ amerge_at_@suff@(@type@ *arr, npy_intp *tosort, const run *stack,
s2 = stack[at + 1].s;
l2 = stack[at + 1].l;
/* tosort[s2] belongs to tosort[s1+k] */
- k = agallop_right_@suff@(arr, tosort + s1, l1, arr + tosort[s2] * len, len);
+ k = agallop_right_<Tag>(arr, tosort + s1, l1, arr + tosort[s2] * len, len);
if (l1 == k) {
/* already sorted */
@@ -1582,30 +1678,35 @@ amerge_at_@suff@(@type@ *arr, npy_intp *tosort, const run *stack,
l1 -= k;
p2 = tosort + s2;
/* tosort[s2-1] belongs to tosort[s2+l2] */
- l2 = agallop_left_@suff@(arr, tosort + s2, l2, arr + tosort[s2 - 1] * len,
- len);
+ l2 = agallop_left_<Tag>(arr, tosort + s2, l2, arr + tosort[s2 - 1] * len,
+ len);
if (l2 < l1) {
ret = resize_buffer_intp(buffer, l2);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
- amerge_right_@suff@(arr, p1, l1, p2, l2, buffer->pw, len);
- } else {
+ amerge_right_<Tag>(arr, p1, l1, p2, l2, buffer->pw, len);
+ }
+ else {
ret = resize_buffer_intp(buffer, l1);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
- amerge_left_@suff@(arr, p1, l1, p2, l2, buffer->pw, len);
+ amerge_left_<Tag>(arr, p1, l1, p2, l2, buffer->pw, len);
}
return 0;
}
-
+template <typename Tag, typename type>
static int
-atry_collapse_@suff@(@type@ *arr, npy_intp *tosort, run *stack,
- npy_intp *stack_ptr, buffer_intp *buffer, size_t len)
+atry_collapse_(type *arr, npy_intp *tosort, run *stack, npy_intp *stack_ptr,
+ buffer_intp *buffer, size_t len)
{
int ret;
npy_intp A, B, C, top;
@@ -1616,33 +1717,44 @@ atry_collapse_@suff@(@type@ *arr, npy_intp *tosort, run *stack,
C = stack[top - 1].l;
if ((2 < top && stack[top - 3].l <= B + C) ||
- (3 < top && stack[top - 4].l <= stack[top - 3].l + B)) {
+ (3 < top && stack[top - 4].l <= stack[top - 3].l + B)) {
A = stack[top - 3].l;
if (A <= C) {
- ret = amerge_at_@suff@(arr, tosort, stack, top - 3, buffer, len);
+ ret = amerge_at_<Tag>(arr, tosort, stack, top - 3, buffer,
+ len);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 3].l += B;
stack[top - 2] = stack[top - 1];
--top;
- } else {
- ret = amerge_at_@suff@(arr, tosort, stack, top - 2, buffer, len);
+ }
+ else {
+ ret = amerge_at_<Tag>(arr, tosort, stack, top - 2, buffer,
+ len);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 2].l += C;
--top;
}
- } else if (1 < top && B <= C) {
- ret = amerge_at_@suff@(arr, tosort, stack, top - 2, buffer, len);
+ }
+ else if (1 < top && B <= C) {
+ ret = amerge_at_<Tag>(arr, tosort, stack, top - 2, buffer, len);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 2].l += C;
--top;
- } else {
+ }
+ else {
break;
}
}
@@ -1651,28 +1763,32 @@ atry_collapse_@suff@(@type@ *arr, npy_intp *tosort, run *stack,
return 0;
}
-
-
+template <typename Tag, typename type>
static int
-aforce_collapse_@suff@(@type@ *arr, npy_intp *tosort, run *stack,
- npy_intp *stack_ptr, buffer_intp *buffer, size_t len)
+aforce_collapse_(type *arr, npy_intp *tosort, run *stack, npy_intp *stack_ptr,
+ buffer_intp *buffer, size_t len)
{
int ret;
npy_intp top = *stack_ptr;
while (2 < top) {
if (stack[top - 3].l <= stack[top - 1].l) {
- ret = amerge_at_@suff@(arr, tosort, stack, top - 3, buffer, len);
+ ret = amerge_at_<Tag>(arr, tosort, stack, top - 3, buffer, len);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 3].l += stack[top - 2].l;
stack[top - 2] = stack[top - 1];
--top;
- } else {
- ret = amerge_at_@suff@(arr, tosort, stack, top - 2, buffer, len);
+ }
+ else {
+ ret = amerge_at_<Tag>(arr, tosort, stack, top - 2, buffer, len);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 2].l += stack[top - 1].l;
--top;
@@ -1680,21 +1796,24 @@ aforce_collapse_@suff@(@type@ *arr, npy_intp *tosort, run *stack,
}
if (1 < top) {
- ret = amerge_at_@suff@(arr, tosort, stack, top - 2, buffer, len);
+ ret = amerge_at_<Tag>(arr, tosort, stack, top - 2, buffer, len);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
}
return 0;
}
-
+template <typename Tag>
NPY_NO_EXPORT int
-atimsort_@suff@(void *start, npy_intp *tosort, npy_intp num, void *varr)
+string_atimsort_(void *start, npy_intp *tosort, npy_intp num, void *varr)
{
- PyArrayObject *arr = varr;
+ using type = typename Tag::type;
+ PyArrayObject *arr = reinterpret_cast<PyArrayObject *>(varr);
size_t elsize = PyArray_ITEMSIZE(arr);
- size_t len = elsize / sizeof(@type@);
+ size_t len = elsize / sizeof(type);
int ret;
npy_intp l, n, stack_ptr, minrun;
run stack[TIMSORT_STACK_SIZE];
@@ -1711,21 +1830,27 @@ atimsort_@suff@(void *start, npy_intp *tosort, npy_intp num, void *varr)
minrun = compute_min_run_short(num);
for (l = 0; l < num;) {
- n = acount_run_@suff@(start, tosort, l, num, minrun, len);
+ n = acount_run_<Tag>((type *)start, tosort, l, num, minrun, len);
/* both s and l are scaled by len */
stack[stack_ptr].s = l;
stack[stack_ptr].l = n;
++stack_ptr;
- ret = atry_collapse_@suff@(start, tosort, stack, &stack_ptr, &buffer, len);
+ ret = atry_collapse_<Tag>((type *)start, tosort, stack, &stack_ptr,
+ &buffer, len);
- if (NPY_UNLIKELY(ret < 0)) { goto cleanup; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ goto cleanup;
+ }
l += n;
}
- ret = aforce_collapse_@suff@(start, tosort, stack, &stack_ptr, &buffer, len);
+ ret = aforce_collapse_<Tag>((type *)start, tosort, stack, &stack_ptr,
+ &buffer, len);
- if (NPY_UNLIKELY(ret < 0)) { goto cleanup; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ goto cleanup;
+ }
ret = 0;
@@ -1736,25 +1861,18 @@ cleanup:
return ret;
}
-
-/**end repeat**/
-
-
-
/*
*****************************************************************************
** GENERIC SORT **
*****************************************************************************
*/
-
typedef struct {
char *pw;
npy_intp size;
size_t len;
} buffer_char;
-
static NPY_INLINE int
resize_buffer_char(buffer_char *buffer, npy_intp new_size)
{
@@ -1763,24 +1881,26 @@ resize_buffer_char(buffer_char *buffer, npy_intp new_size)
}
if (NPY_UNLIKELY(buffer->pw == NULL)) {
- buffer->pw = malloc(sizeof(char) * new_size * buffer->len);
- } else {
- buffer->pw = realloc(buffer->pw, sizeof(char) * new_size * buffer->len);
+ buffer->pw = (char *)malloc(sizeof(char) * new_size * buffer->len);
+ }
+ else {
+ buffer->pw = (char *)realloc(buffer->pw,
+ sizeof(char) * new_size * buffer->len);
}
buffer->size = new_size;
if (NPY_UNLIKELY(buffer->pw == NULL)) {
return -NPY_ENOMEM;
- } else {
+ }
+ else {
return 0;
}
}
-
static npy_intp
-npy_count_run(char *arr, npy_intp l, npy_intp num, npy_intp minrun,
- char *vp, size_t len, PyArray_CompareFunc *cmp, PyArrayObject *py_arr)
+npy_count_run(char *arr, npy_intp l, npy_intp num, npy_intp minrun, char *vp,
+ size_t len, PyArray_CompareFunc *cmp, PyArrayObject *py_arr)
{
npy_intp sz;
char *pl, *pi, *pj, *pr;
@@ -1793,12 +1913,15 @@ npy_count_run(char *arr, npy_intp l, npy_intp num, npy_intp minrun,
/* (not strictly) ascending sequence */
if (cmp(pl, pl + len, py_arr) <= 0) {
- for (pi = pl + len; pi < arr + (num - 1) * len
- && cmp(pi, pi + len, py_arr) <= 0; pi += len) {
+ for (pi = pl + len;
+ pi < arr + (num - 1) * len && cmp(pi, pi + len, py_arr) <= 0;
+ pi += len) {
}
- } else { /* (strictly) descending sequence */
- for (pi = pl + len; pi < arr + (num - 1) * len
- && cmp(pi + len, pi, py_arr) < 0; pi += len) {
+ }
+ else { /* (strictly) descending sequence */
+ for (pi = pl + len;
+ pi < arr + (num - 1) * len && cmp(pi + len, pi, py_arr) < 0;
+ pi += len) {
}
for (pj = pl, pr = pi; pj < pr; pj += len, pr -= len) {
@@ -1812,7 +1935,8 @@ npy_count_run(char *arr, npy_intp l, npy_intp num, npy_intp minrun,
if (sz < minrun) {
if (l + minrun < num) {
sz = minrun;
- } else {
+ }
+ else {
sz = num - l;
}
@@ -1835,7 +1959,6 @@ npy_count_run(char *arr, npy_intp l, npy_intp num, npy_intp minrun,
return sz;
}
-
static npy_intp
npy_gallop_right(const char *arr, const npy_intp size, const char *key,
size_t len, PyArray_CompareFunc *cmp, PyArrayObject *py_arr)
@@ -1857,7 +1980,8 @@ npy_gallop_right(const char *arr, const npy_intp size, const char *key,
if (cmp(key, arr + ofs * len, py_arr) < 0) {
break;
- } else {
+ }
+ else {
last_ofs = ofs;
/* ofs = 1, 3, 7, 15... */
ofs = (ofs << 1) + 1;
@@ -1870,7 +1994,8 @@ npy_gallop_right(const char *arr, const npy_intp size, const char *key,
if (cmp(key, arr + m * len, py_arr) < 0) {
ofs = m;
- } else {
+ }
+ else {
last_ofs = m;
}
}
@@ -1879,8 +2004,6 @@ npy_gallop_right(const char *arr, const npy_intp size, const char *key,
return ofs;
}
-
-
static npy_intp
npy_gallop_left(const char *arr, const npy_intp size, const char *key,
size_t len, PyArray_CompareFunc *cmp, PyArrayObject *py_arr)
@@ -1902,7 +2025,8 @@ npy_gallop_left(const char *arr, const npy_intp size, const char *key,
if (cmp(arr + (size - ofs - 1) * len, key, py_arr) < 0) {
break;
- } else {
+ }
+ else {
last_ofs = ofs;
ofs = (ofs << 1) + 1;
}
@@ -1917,7 +2041,8 @@ npy_gallop_left(const char *arr, const npy_intp size, const char *key,
if (cmp(arr + m * len, key, py_arr) < 0) {
l = m;
- } else {
+ }
+ else {
r = m;
}
}
@@ -1926,11 +2051,9 @@ npy_gallop_left(const char *arr, const npy_intp size, const char *key,
return r;
}
-
static void
-npy_merge_left(char *p1, npy_intp l1, char *p2, npy_intp l2,
- char *p3, size_t len,
- PyArray_CompareFunc *cmp, PyArrayObject *py_arr)
+npy_merge_left(char *p1, npy_intp l1, char *p2, npy_intp l2, char *p3,
+ size_t len, PyArray_CompareFunc *cmp, PyArrayObject *py_arr)
{
char *end = p2 + l2 * len;
memcpy(p3, p1, sizeof(char) * l1 * len);
@@ -1944,7 +2067,8 @@ npy_merge_left(char *p1, npy_intp l1, char *p2, npy_intp l2,
GENERIC_COPY(p1, p2, len);
p1 += len;
p2 += len;
- } else {
+ }
+ else {
GENERIC_COPY(p1, p3, len);
p1 += len;
p3 += len;
@@ -1956,11 +2080,9 @@ npy_merge_left(char *p1, npy_intp l1, char *p2, npy_intp l2,
}
}
-
static void
-npy_merge_right(char *p1, npy_intp l1, char *p2, npy_intp l2,
- char *p3, size_t len,
- PyArray_CompareFunc *cmp, PyArrayObject *py_arr)
+npy_merge_right(char *p1, npy_intp l1, char *p2, npy_intp l2, char *p3,
+ size_t len, PyArray_CompareFunc *cmp, PyArrayObject *py_arr)
{
npy_intp ofs;
char *start = p1 - len;
@@ -1978,7 +2100,8 @@ npy_merge_right(char *p1, npy_intp l1, char *p2, npy_intp l2,
GENERIC_COPY(p2, p1, len);
p2 -= len;
p1 -= len;
- } else {
+ }
+ else {
GENERIC_COPY(p2, p3, len);
p2 -= len;
p3 -= len;
@@ -1991,12 +2114,10 @@ npy_merge_right(char *p1, npy_intp l1, char *p2, npy_intp l2,
}
}
-
-
static int
npy_merge_at(char *arr, const run *stack, const npy_intp at,
- buffer_char *buffer, size_t len,
- PyArray_CompareFunc *cmp, PyArrayObject *py_arr)
+ buffer_char *buffer, size_t len, PyArray_CompareFunc *cmp,
+ PyArrayObject *py_arr)
{
int ret;
npy_intp s1, l1, s2, l2, k;
@@ -2024,13 +2145,18 @@ npy_merge_at(char *arr, const run *stack, const npy_intp at,
if (l2 < l1) {
ret = resize_buffer_char(buffer, l2);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
npy_merge_right(p1, l1, p2, l2, buffer->pw, len, cmp, py_arr);
- } else {
+ }
+ else {
ret = resize_buffer_char(buffer, l1);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
npy_merge_left(p1, l1, p2, l2, buffer->pw, len, cmp, py_arr);
}
@@ -2038,11 +2164,10 @@ npy_merge_at(char *arr, const run *stack, const npy_intp at,
return 0;
}
-
static int
npy_try_collapse(char *arr, run *stack, npy_intp *stack_ptr,
- buffer_char *buffer, size_t len,
- PyArray_CompareFunc *cmp, PyArrayObject *py_arr)
+ buffer_char *buffer, size_t len, PyArray_CompareFunc *cmp,
+ PyArrayObject *py_arr)
{
int ret;
npy_intp A, B, C, top;
@@ -2053,33 +2178,44 @@ npy_try_collapse(char *arr, run *stack, npy_intp *stack_ptr,
C = stack[top - 1].l;
if ((2 < top && stack[top - 3].l <= B + C) ||
- (3 < top && stack[top - 4].l <= stack[top - 3].l + B)) {
+ (3 < top && stack[top - 4].l <= stack[top - 3].l + B)) {
A = stack[top - 3].l;
if (A <= C) {
- ret = npy_merge_at(arr, stack, top - 3, buffer, len, cmp, py_arr);
+ ret = npy_merge_at(arr, stack, top - 3, buffer, len, cmp,
+ py_arr);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 3].l += B;
stack[top - 2] = stack[top - 1];
--top;
- } else {
- ret = npy_merge_at(arr, stack, top - 2, buffer, len, cmp, py_arr);
+ }
+ else {
+ ret = npy_merge_at(arr, stack, top - 2, buffer, len, cmp,
+ py_arr);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 2].l += C;
--top;
}
- } else if (1 < top && B <= C) {
+ }
+ else if (1 < top && B <= C) {
ret = npy_merge_at(arr, stack, top - 2, buffer, len, cmp, py_arr);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 2].l += C;
--top;
- } else {
+ }
+ else {
break;
}
}
@@ -2088,11 +2224,10 @@ npy_try_collapse(char *arr, run *stack, npy_intp *stack_ptr,
return 0;
}
-
static int
npy_force_collapse(char *arr, run *stack, npy_intp *stack_ptr,
- buffer_char *buffer, size_t len,
- PyArray_CompareFunc *cmp, PyArrayObject *py_arr)
+ buffer_char *buffer, size_t len, PyArray_CompareFunc *cmp,
+ PyArrayObject *py_arr)
{
int ret;
npy_intp top = *stack_ptr;
@@ -2101,15 +2236,20 @@ npy_force_collapse(char *arr, run *stack, npy_intp *stack_ptr,
if (stack[top - 3].l <= stack[top - 1].l) {
ret = npy_merge_at(arr, stack, top - 3, buffer, len, cmp, py_arr);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 3].l += stack[top - 2].l;
stack[top - 2] = stack[top - 1];
--top;
- } else {
+ }
+ else {
ret = npy_merge_at(arr, stack, top - 2, buffer, len, cmp, py_arr);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 2].l += stack[top - 1].l;
--top;
@@ -2119,17 +2259,18 @@ npy_force_collapse(char *arr, run *stack, npy_intp *stack_ptr,
if (1 < top) {
ret = npy_merge_at(arr, stack, top - 2, buffer, len, cmp, py_arr);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
}
return 0;
}
-
NPY_NO_EXPORT int
npy_timsort(void *start, npy_intp num, void *varr)
{
- PyArrayObject *arr = varr;
+ PyArrayObject *arr = reinterpret_cast<PyArrayObject *>(varr);
size_t len = PyArray_ITEMSIZE(arr);
PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare;
int ret;
@@ -2151,25 +2292,34 @@ npy_timsort(void *start, npy_intp num, void *varr)
/* used for insertion sort and gallop key */
ret = resize_buffer_char(&buffer, len);
- if (NPY_UNLIKELY(ret < 0)) { goto cleanup; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ goto cleanup;
+ }
for (l = 0; l < num;) {
- n = npy_count_run(start, l, num, minrun, buffer.pw, len, cmp, arr);
+ n = npy_count_run((char *)start, l, num, minrun, buffer.pw, len, cmp,
+ arr);
/* both s and l are scaled by len */
stack[stack_ptr].s = l;
stack[stack_ptr].l = n;
++stack_ptr;
- ret = npy_try_collapse(start, stack, &stack_ptr, &buffer, len, cmp, arr);
+ ret = npy_try_collapse((char *)start, stack, &stack_ptr, &buffer, len,
+ cmp, arr);
- if (NPY_UNLIKELY(ret < 0)) { goto cleanup; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ goto cleanup;
+ }
l += n;
}
- ret = npy_force_collapse(start, stack, &stack_ptr, &buffer, len, cmp, arr);
+ ret = npy_force_collapse((char *)start, stack, &stack_ptr, &buffer, len,
+ cmp, arr);
- if (NPY_UNLIKELY(ret < 0)) { goto cleanup; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ goto cleanup;
+ }
ret = 0;
@@ -2180,13 +2330,12 @@ cleanup:
return ret;
}
-
/* argsort */
static npy_intp
npy_acount_run(char *arr, npy_intp *tosort, npy_intp l, npy_intp num,
- npy_intp minrun, size_t len,
- PyArray_CompareFunc *cmp, PyArrayObject *py_arr)
+ npy_intp minrun, size_t len, PyArray_CompareFunc *cmp,
+ PyArrayObject *py_arr)
{
npy_intp sz;
npy_intp vi;
@@ -2200,16 +2349,21 @@ npy_acount_run(char *arr, npy_intp *tosort, npy_intp l, npy_intp num,
/* (not strictly) ascending sequence */
if (cmp(arr + (*pl) * len, arr + (*(pl + 1)) * len, py_arr) <= 0) {
- for (pi = pl + 1; pi < tosort + num - 1
- && cmp(arr + (*pi) * len, arr + (*(pi + 1)) * len, py_arr) <= 0; ++pi) {
+ for (pi = pl + 1;
+ pi < tosort + num - 1 &&
+ cmp(arr + (*pi) * len, arr + (*(pi + 1)) * len, py_arr) <= 0;
+ ++pi) {
}
- } else { /* (strictly) descending sequence */
- for (pi = pl + 1; pi < tosort + num - 1
- && cmp(arr + (*(pi + 1)) * len, arr + (*pi) * len, py_arr) < 0; ++pi) {
+ }
+ else { /* (strictly) descending sequence */
+ for (pi = pl + 1;
+ pi < tosort + num - 1 &&
+ cmp(arr + (*(pi + 1)) * len, arr + (*pi) * len, py_arr) < 0;
+ ++pi) {
}
for (pj = pl, pr = pi; pj < pr; ++pj, --pr) {
- INTP_SWAP(*pj, *pr);
+ std::swap(*pj, *pr);
}
}
@@ -2219,7 +2373,8 @@ npy_acount_run(char *arr, npy_intp *tosort, npy_intp l, npy_intp num,
if (sz < minrun) {
if (l + minrun < num) {
sz = minrun;
- } else {
+ }
+ else {
sz = num - l;
}
@@ -2230,7 +2385,8 @@ npy_acount_run(char *arr, npy_intp *tosort, npy_intp l, npy_intp num,
vi = *pi;
pj = pi;
- while (pl < pj && cmp(arr + vi * len, arr + (*(pj - 1)) * len, py_arr) < 0) {
+ while (pl < pj &&
+ cmp(arr + vi * len, arr + (*(pj - 1)) * len, py_arr) < 0) {
*pj = *(pj - 1);
--pj;
}
@@ -2242,11 +2398,10 @@ npy_acount_run(char *arr, npy_intp *tosort, npy_intp l, npy_intp num,
return sz;
}
-
static npy_intp
-npy_agallop_left(const char *arr, const npy_intp *tosort,
- const npy_intp size, const char *key, size_t len,
- PyArray_CompareFunc *cmp, PyArrayObject *py_arr)
+npy_agallop_left(const char *arr, const npy_intp *tosort, const npy_intp size,
+ const char *key, size_t len, PyArray_CompareFunc *cmp,
+ PyArrayObject *py_arr)
{
npy_intp last_ofs, ofs, l, m, r;
@@ -2265,13 +2420,15 @@ npy_agallop_left(const char *arr, const npy_intp *tosort,
if (cmp(arr + tosort[size - ofs - 1] * len, key, py_arr) < 0) {
break;
- } else {
+ }
+ else {
last_ofs = ofs;
ofs = (ofs << 1) + 1;
}
}
- /* now that arr[tosort[size-ofs-1]*len] < key <= arr[tosort[size-last_ofs-1]*len] */
+ /* now that arr[tosort[size-ofs-1]*len] < key <=
+ * arr[tosort[size-last_ofs-1]*len] */
l = size - ofs - 1;
r = size - last_ofs - 1;
@@ -2280,7 +2437,8 @@ npy_agallop_left(const char *arr, const npy_intp *tosort,
if (cmp(arr + tosort[m] * len, key, py_arr) < 0) {
l = m;
- } else {
+ }
+ else {
r = m;
}
}
@@ -2289,11 +2447,10 @@ npy_agallop_left(const char *arr, const npy_intp *tosort,
return r;
}
-
static npy_intp
-npy_agallop_right(const char *arr, const npy_intp *tosort,
- const npy_intp size, const char *key, size_t len,
- PyArray_CompareFunc *cmp, PyArrayObject *py_arr)
+npy_agallop_right(const char *arr, const npy_intp *tosort, const npy_intp size,
+ const char *key, size_t len, PyArray_CompareFunc *cmp,
+ PyArrayObject *py_arr)
{
npy_intp last_ofs, ofs, m;
@@ -2312,7 +2469,8 @@ npy_agallop_right(const char *arr, const npy_intp *tosort,
if (cmp(key, arr + tosort[ofs] * len, py_arr) < 0) {
break;
- } else {
+ }
+ else {
last_ofs = ofs;
/* ofs = 1, 3, 7, 15... */
ofs = (ofs << 1) + 1;
@@ -2325,7 +2483,8 @@ npy_agallop_right(const char *arr, const npy_intp *tosort,
if (cmp(key, arr + tosort[m] * len, py_arr) < 0) {
ofs = m;
- } else {
+ }
+ else {
last_ofs = m;
}
}
@@ -2334,7 +2493,6 @@ npy_agallop_right(const char *arr, const npy_intp *tosort,
return ofs;
}
-
static void
npy_amerge_left(char *arr, npy_intp *p1, npy_intp l1, npy_intp *p2,
npy_intp l2, npy_intp *p3, size_t len,
@@ -2348,7 +2506,8 @@ npy_amerge_left(char *arr, npy_intp *p1, npy_intp l1, npy_intp *p2,
while (p1 < p2 && p2 < end) {
if (cmp(arr + (*p2) * len, arr + (*p3) * len, py_arr) < 0) {
*p1++ = *p2++;
- } else {
+ }
+ else {
*p1++ = *p3++;
}
}
@@ -2358,9 +2517,8 @@ npy_amerge_left(char *arr, npy_intp *p1, npy_intp l1, npy_intp *p2,
}
}
-
static void
-npy_amerge_right(char *arr, npy_intp* p1, npy_intp l1, npy_intp *p2,
+npy_amerge_right(char *arr, npy_intp *p1, npy_intp l1, npy_intp *p2,
npy_intp l2, npy_intp *p3, size_t len,
PyArray_CompareFunc *cmp, PyArrayObject *py_arr)
{
@@ -2376,7 +2534,8 @@ npy_amerge_right(char *arr, npy_intp* p1, npy_intp l1, npy_intp *p2,
while (p1 < p2 && start < p1) {
if (cmp(arr + (*p3) * len, arr + (*p1) * len, py_arr) < 0) {
*p2-- = *p1--;
- } else {
+ }
+ else {
*p2-- = *p3--;
}
}
@@ -2387,12 +2546,10 @@ npy_amerge_right(char *arr, npy_intp* p1, npy_intp l1, npy_intp *p2,
}
}
-
-
static int
-npy_amerge_at(char *arr, npy_intp *tosort, const run *stack,
- const npy_intp at, buffer_intp *buffer, size_t len,
- PyArray_CompareFunc *cmp, PyArrayObject *py_arr)
+npy_amerge_at(char *arr, npy_intp *tosort, const run *stack, const npy_intp at,
+ buffer_intp *buffer, size_t len, PyArray_CompareFunc *cmp,
+ PyArrayObject *py_arr)
{
int ret;
npy_intp s1, l1, s2, l2, k;
@@ -2402,8 +2559,8 @@ npy_amerge_at(char *arr, npy_intp *tosort, const run *stack,
s2 = stack[at + 1].s;
l2 = stack[at + 1].l;
/* tosort[s2] belongs to tosort[s1+k] */
- k = npy_agallop_right(arr, tosort + s1, l1, arr + tosort[s2] * len, len, cmp,
- py_arr);
+ k = npy_agallop_right(arr, tosort + s1, l1, arr + tosort[s2] * len, len,
+ cmp, py_arr);
if (l1 == k) {
/* already sorted */
@@ -2420,13 +2577,18 @@ npy_amerge_at(char *arr, npy_intp *tosort, const run *stack,
if (l2 < l1) {
ret = resize_buffer_intp(buffer, l2);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
npy_amerge_right(arr, p1, l1, p2, l2, buffer->pw, len, cmp, py_arr);
- } else {
+ }
+ else {
ret = resize_buffer_intp(buffer, l1);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
npy_amerge_left(arr, p1, l1, p2, l2, buffer->pw, len, cmp, py_arr);
}
@@ -2434,11 +2596,10 @@ npy_amerge_at(char *arr, npy_intp *tosort, const run *stack,
return 0;
}
-
static int
-npy_atry_collapse(char *arr, npy_intp *tosort, run *stack,
- npy_intp *stack_ptr, buffer_intp *buffer, size_t len,
- PyArray_CompareFunc *cmp, PyArrayObject *py_arr)
+npy_atry_collapse(char *arr, npy_intp *tosort, run *stack, npy_intp *stack_ptr,
+ buffer_intp *buffer, size_t len, PyArray_CompareFunc *cmp,
+ PyArrayObject *py_arr)
{
int ret;
npy_intp A, B, C, top;
@@ -2449,33 +2610,45 @@ npy_atry_collapse(char *arr, npy_intp *tosort, run *stack,
C = stack[top - 1].l;
if ((2 < top && stack[top - 3].l <= B + C) ||
- (3 < top && stack[top - 4].l <= stack[top - 3].l + B)) {
+ (3 < top && stack[top - 4].l <= stack[top - 3].l + B)) {
A = stack[top - 3].l;
if (A <= C) {
- ret = npy_amerge_at(arr, tosort, stack, top - 3, buffer, len, cmp, py_arr);
+ ret = npy_amerge_at(arr, tosort, stack, top - 3, buffer, len,
+ cmp, py_arr);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 3].l += B;
stack[top - 2] = stack[top - 1];
--top;
- } else {
- ret = npy_amerge_at(arr, tosort, stack, top - 2, buffer, len, cmp, py_arr);
+ }
+ else {
+ ret = npy_amerge_at(arr, tosort, stack, top - 2, buffer, len,
+ cmp, py_arr);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 2].l += C;
--top;
}
- } else if (1 < top && B <= C) {
- ret = npy_amerge_at(arr, tosort, stack, top - 2, buffer, len, cmp, py_arr);
+ }
+ else if (1 < top && B <= C) {
+ ret = npy_amerge_at(arr, tosort, stack, top - 2, buffer, len, cmp,
+ py_arr);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 2].l += C;
--top;
- } else {
+ }
+ else {
break;
}
}
@@ -2484,7 +2657,6 @@ npy_atry_collapse(char *arr, npy_intp *tosort, run *stack,
return 0;
}
-
static int
npy_aforce_collapse(char *arr, npy_intp *tosort, run *stack,
npy_intp *stack_ptr, buffer_intp *buffer, size_t len,
@@ -2495,17 +2667,24 @@ npy_aforce_collapse(char *arr, npy_intp *tosort, run *stack,
while (2 < top) {
if (stack[top - 3].l <= stack[top - 1].l) {
- ret = npy_amerge_at(arr, tosort, stack, top - 3, buffer, len, cmp, py_arr);
+ ret = npy_amerge_at(arr, tosort, stack, top - 3, buffer, len, cmp,
+ py_arr);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 3].l += stack[top - 2].l;
stack[top - 2] = stack[top - 1];
--top;
- } else {
- ret = npy_amerge_at(arr, tosort, stack, top - 2, buffer, len, cmp, py_arr);
+ }
+ else {
+ ret = npy_amerge_at(arr, tosort, stack, top - 2, buffer, len, cmp,
+ py_arr);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
stack[top - 2].l += stack[top - 1].l;
--top;
@@ -2513,19 +2692,21 @@ npy_aforce_collapse(char *arr, npy_intp *tosort, run *stack,
}
if (1 < top) {
- ret = npy_amerge_at(arr, tosort, stack, top - 2, buffer, len, cmp, py_arr);
+ ret = npy_amerge_at(arr, tosort, stack, top - 2, buffer, len, cmp,
+ py_arr);
- if (NPY_UNLIKELY(ret < 0)) { return ret; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ return ret;
+ }
}
return 0;
}
-
NPY_NO_EXPORT int
npy_atimsort(void *start, npy_intp *tosort, npy_intp num, void *varr)
{
- PyArrayObject *arr = varr;
+ PyArrayObject *arr = reinterpret_cast<PyArrayObject *>(varr);
size_t len = PyArray_ITEMSIZE(arr);
PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare;
int ret;
@@ -2544,23 +2725,28 @@ npy_atimsort(void *start, npy_intp *tosort, npy_intp num, void *varr)
minrun = compute_min_run_short(num);
for (l = 0; l < num;) {
- n = npy_acount_run(start, tosort, l, num, minrun, len, cmp, arr);
+ n = npy_acount_run((char *)start, tosort, l, num, minrun, len, cmp,
+ arr);
/* both s and l are scaled by len */
stack[stack_ptr].s = l;
stack[stack_ptr].l = n;
++stack_ptr;
- ret = npy_atry_collapse(start, tosort, stack, &stack_ptr, &buffer, len, cmp,
- arr);
+ ret = npy_atry_collapse((char *)start, tosort, stack, &stack_ptr,
+ &buffer, len, cmp, arr);
- if (NPY_UNLIKELY(ret < 0)) { goto cleanup; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ goto cleanup;
+ }
l += n;
}
- ret = npy_aforce_collapse(start, tosort, stack, &stack_ptr, &buffer, len,
- cmp, arr);
+ ret = npy_aforce_collapse((char *)start, tosort, stack, &stack_ptr,
+ &buffer, len, cmp, arr);
- if (NPY_UNLIKELY(ret < 0)) { goto cleanup; }
+ if (NPY_UNLIKELY(ret < 0)) {
+ goto cleanup;
+ }
ret = 0;
@@ -2570,3 +2756,239 @@ cleanup:
}
return ret;
}
+
+/***************************************
+ * C > C++ dispatch
+ ***************************************/
+
+NPY_NO_EXPORT int
+timsort_bool(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return timsort_<npy::bool_tag>(start, num);
+}
+NPY_NO_EXPORT int
+timsort_byte(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return timsort_<npy::byte_tag>(start, num);
+}
+NPY_NO_EXPORT int
+timsort_ubyte(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return timsort_<npy::ubyte_tag>(start, num);
+}
+NPY_NO_EXPORT int
+timsort_short(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return timsort_<npy::short_tag>(start, num);
+}
+NPY_NO_EXPORT int
+timsort_ushort(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return timsort_<npy::ushort_tag>(start, num);
+}
+NPY_NO_EXPORT int
+timsort_int(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return timsort_<npy::int_tag>(start, num);
+}
+NPY_NO_EXPORT int
+timsort_uint(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return timsort_<npy::uint_tag>(start, num);
+}
+NPY_NO_EXPORT int
+timsort_long(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return timsort_<npy::long_tag>(start, num);
+}
+NPY_NO_EXPORT int
+timsort_ulong(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return timsort_<npy::ulong_tag>(start, num);
+}
+NPY_NO_EXPORT int
+timsort_longlong(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return timsort_<npy::longlong_tag>(start, num);
+}
+NPY_NO_EXPORT int
+timsort_ulonglong(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return timsort_<npy::ulonglong_tag>(start, num);
+}
+NPY_NO_EXPORT int
+timsort_half(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return timsort_<npy::half_tag>(start, num);
+}
+NPY_NO_EXPORT int
+timsort_float(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return timsort_<npy::float_tag>(start, num);
+}
+NPY_NO_EXPORT int
+timsort_double(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return timsort_<npy::double_tag>(start, num);
+}
+NPY_NO_EXPORT int
+timsort_longdouble(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return timsort_<npy::longdouble_tag>(start, num);
+}
+NPY_NO_EXPORT int
+timsort_cfloat(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return timsort_<npy::cfloat_tag>(start, num);
+}
+NPY_NO_EXPORT int
+timsort_cdouble(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return timsort_<npy::cdouble_tag>(start, num);
+}
+NPY_NO_EXPORT int
+timsort_clongdouble(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return timsort_<npy::clongdouble_tag>(start, num);
+}
+NPY_NO_EXPORT int
+timsort_datetime(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return timsort_<npy::datetime_tag>(start, num);
+}
+NPY_NO_EXPORT int
+timsort_timedelta(void *start, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return timsort_<npy::timedelta_tag>(start, num);
+}
+NPY_NO_EXPORT int
+timsort_string(void *start, npy_intp num, void *varr)
+{
+ return string_timsort_<npy::string_tag>(start, num, varr);
+}
+NPY_NO_EXPORT int
+timsort_unicode(void *start, npy_intp num, void *varr)
+{
+ return string_timsort_<npy::unicode_tag>(start, num, varr);
+}
+
+NPY_NO_EXPORT int
+atimsort_bool(void *v, npy_intp *tosort, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return atimsort_<npy::bool_tag>(v, tosort, num);
+}
+NPY_NO_EXPORT int
+atimsort_byte(void *v, npy_intp *tosort, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return atimsort_<npy::byte_tag>(v, tosort, num);
+}
+NPY_NO_EXPORT int
+atimsort_ubyte(void *v, npy_intp *tosort, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return atimsort_<npy::ubyte_tag>(v, tosort, num);
+}
+NPY_NO_EXPORT int
+atimsort_short(void *v, npy_intp *tosort, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return atimsort_<npy::short_tag>(v, tosort, num);
+}
+NPY_NO_EXPORT int
+atimsort_ushort(void *v, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return atimsort_<npy::ushort_tag>(v, tosort, num);
+}
+NPY_NO_EXPORT int
+atimsort_int(void *v, npy_intp *tosort, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return atimsort_<npy::int_tag>(v, tosort, num);
+}
+NPY_NO_EXPORT int
+atimsort_uint(void *v, npy_intp *tosort, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return atimsort_<npy::uint_tag>(v, tosort, num);
+}
+NPY_NO_EXPORT int
+atimsort_long(void *v, npy_intp *tosort, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return atimsort_<npy::long_tag>(v, tosort, num);
+}
+NPY_NO_EXPORT int
+atimsort_ulong(void *v, npy_intp *tosort, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return atimsort_<npy::ulong_tag>(v, tosort, num);
+}
+NPY_NO_EXPORT int
+atimsort_longlong(void *v, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return atimsort_<npy::longlong_tag>(v, tosort, num);
+}
+NPY_NO_EXPORT int
+atimsort_ulonglong(void *v, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return atimsort_<npy::ulonglong_tag>(v, tosort, num);
+}
+NPY_NO_EXPORT int
+atimsort_half(void *v, npy_intp *tosort, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return atimsort_<npy::half_tag>(v, tosort, num);
+}
+NPY_NO_EXPORT int
+atimsort_float(void *v, npy_intp *tosort, npy_intp num, void *NPY_UNUSED(varr))
+{
+ return atimsort_<npy::float_tag>(v, tosort, num);
+}
+NPY_NO_EXPORT int
+atimsort_double(void *v, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return atimsort_<npy::double_tag>(v, tosort, num);
+}
+NPY_NO_EXPORT int
+atimsort_longdouble(void *v, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return atimsort_<npy::longdouble_tag>(v, tosort, num);
+}
+NPY_NO_EXPORT int
+atimsort_cfloat(void *v, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return atimsort_<npy::cfloat_tag>(v, tosort, num);
+}
+NPY_NO_EXPORT int
+atimsort_cdouble(void *v, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return atimsort_<npy::cdouble_tag>(v, tosort, num);
+}
+NPY_NO_EXPORT int
+atimsort_clongdouble(void *v, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return atimsort_<npy::clongdouble_tag>(v, tosort, num);
+}
+NPY_NO_EXPORT int
+atimsort_datetime(void *v, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return atimsort_<npy::datetime_tag>(v, tosort, num);
+}
+NPY_NO_EXPORT int
+atimsort_timedelta(void *v, npy_intp *tosort, npy_intp num,
+ void *NPY_UNUSED(varr))
+{
+ return atimsort_<npy::timedelta_tag>(v, tosort, num);
+}
+NPY_NO_EXPORT int
+atimsort_string(void *v, npy_intp *tosort, npy_intp num, void *varr)
+{
+ return string_atimsort_<npy::string_tag>(v, tosort, num, varr);
+}
+NPY_NO_EXPORT int
+atimsort_unicode(void *v, npy_intp *tosort, npy_intp num, void *varr)
+{
+ return string_atimsort_<npy::unicode_tag>(v, tosort, num, varr);
+}
diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src
index 5f054d0a9..7f084ac39 100644
--- a/numpy/core/src/umath/loops.c.src
+++ b/numpy/core/src/umath/loops.c.src
@@ -1506,62 +1506,6 @@ TIMEDELTA_mm_qm_divmod(char **args, npy_intp const *dimensions, npy_intp const *
*/
/**begin repeat
- * #func = rint, floor, trunc#
- * #scalarf = npy_rint, npy_floor, npy_trunc#
- */
-
-/**begin repeat1
-* #TYPE = FLOAT, DOUBLE#
-* #type = npy_float, npy_double#
-* #typesub = f, #
-*/
-
-NPY_NO_EXPORT NPY_GCC_OPT_3 void
-@TYPE@_@func@(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(data))
-{
- UNARY_LOOP {
- const @type@ in1 = *(@type@ *)ip1;
- *(@type@ *)op1 = @scalarf@@typesub@(in1);
- }
-}
-
-
-/**end repeat1**/
-/**end repeat**/
-
-/**begin repeat
- * #isa = avx512f, fma#
- * #ISA = AVX512F, FMA#
- * #CHK = HAVE_ATTRIBUTE_TARGET_AVX512F_WITH_INTRINSICS, HAVE_ATTRIBUTE_TARGET_AVX2_WITH_INTRINSICS#
- */
-
-/**begin repeat1
- * #TYPE = FLOAT, DOUBLE#
- * #type = npy_float, npy_double#
- * #typesub = f, #
- */
-
-/**begin repeat2
- * #func = rint, floor, trunc#
- * #scalarf = npy_rint, npy_floor, npy_trunc#
- */
-
-NPY_NO_EXPORT NPY_GCC_OPT_3 void
-@TYPE@_@func@_@isa@(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(data))
-{
- if (!run_unary_@isa@_@func@_@TYPE@(args, dimensions, steps)) {
- UNARY_LOOP {
- const @type@ in1 = *(@type@ *)ip1;
- *(@type@ *)op1 = @scalarf@@typesub@(in1);
- }
- }
-}
-
-/**end repeat2**/
-/**end repeat1**/
-/**end repeat**/
-
-/**begin repeat
* Float types
* #type = npy_float, npy_double, npy_longdouble#
* #TYPE = FLOAT, DOUBLE, LONGDOUBLE#
diff --git a/numpy/core/src/umath/loops.h.src b/numpy/core/src/umath/loops.h.src
index 3eafbdf66..e5235b464 100644
--- a/numpy/core/src/umath/loops.h.src
+++ b/numpy/core/src/umath/loops.h.src
@@ -186,7 +186,7 @@ NPY_NO_EXPORT void
* #TYPE = FLOAT, DOUBLE#
*/
/**begin repeat1
- * #kind = ceil, sqrt, absolute, square, reciprocal#
+ * #kind = rint, floor, trunc, ceil, sqrt, absolute, square, reciprocal#
*/
NPY_CPU_DISPATCH_DECLARE(NPY_NO_EXPORT void @TYPE@_@kind@,
(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(data)))
@@ -274,26 +274,6 @@ NPY_CPU_DISPATCH_DECLARE(NPY_NO_EXPORT void @TYPE@_@kind@, (
/**end repeat**/
/**begin repeat
- * #func = rint, floor, trunc#
- */
-
-/**begin repeat1
-* #TYPE = FLOAT, DOUBLE#
-*/
-
-NPY_NO_EXPORT NPY_GCC_OPT_3 void
-@TYPE@_@func@(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(data));
-
-/**begin repeat2
- * #isa = avx512f, fma#
- */
-NPY_NO_EXPORT NPY_GCC_OPT_3 void
-@TYPE@_@func@_@isa@(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(data));
-/**end repeat2**/
-/**end repeat1**/
-/**end repeat**/
-
-/**begin repeat
* Float types
* #TYPE = HALF, FLOAT, DOUBLE, LONGDOUBLE#
* #c = f, f, , l#
diff --git a/numpy/core/src/umath/loops_unary_fp.dispatch.c.src b/numpy/core/src/umath/loops_unary_fp.dispatch.c.src
index 93761b98c..78e231965 100644
--- a/numpy/core/src/umath/loops_unary_fp.dispatch.c.src
+++ b/numpy/core/src/umath/loops_unary_fp.dispatch.c.src
@@ -70,6 +70,15 @@ NPY_FINLINE double c_square_f64(double a)
#define c_ceil_f32 npy_ceilf
#define c_ceil_f64 npy_ceil
+#define c_trunc_f32 npy_truncf
+#define c_trunc_f64 npy_trunc
+
+#define c_floor_f32 npy_floorf
+#define c_floor_f64 npy_floor
+
+#define c_rint_f32 npy_rintf
+#define c_rint_f64 npy_rint
+
/********************************************************************************
** Defining the SIMD kernels
********************************************************************************/
@@ -119,6 +128,9 @@ NPY_FINLINE double c_square_f64(double a)
#if __clang_major__ < 10
// Clang before v10
#define WORKAROUND_CLANG_RECIPROCAL_BUG 1
+ #elif defined(_MSC_VER)
+ // clang-cl has the same bug
+ #define WORKAROUND_CLANG_RECIPROCAL_BUG 1
#elif defined(NPY_CPU_X86) || defined(NPY_CPU_AMD64)
// Clang v10+, targeting i386 or x86_64
#define WORKAROUND_CLANG_RECIPROCAL_BUG 0
@@ -139,10 +151,10 @@ NPY_FINLINE double c_square_f64(double a)
*/
#if @VCHK@
/**begin repeat1
- * #kind = ceil, sqrt, absolute, square, reciprocal#
- * #intr = ceil, sqrt, abs, square, recip#
- * #repl_0w1 = 0, 0, 0, 0, 1#
- * #RECIP_WORKAROUND = 0, 0, 0, 0, WORKAROUND_CLANG_RECIPROCAL_BUG#
+ * #kind = rint, floor, ceil, trunc, sqrt, absolute, square, reciprocal#
+ * #intr = rint, floor, ceil, trunc, sqrt, abs, square, recip#
+ * #repl_0w1 = 0*7, 1#
+ * #RECIP_WORKAROUND = 0*7, WORKAROUND_CLANG_RECIPROCAL_BUG#
*/
/**begin repeat2
* #STYPE = CONTIG, NCONTIG, CONTIG, NCONTIG#
@@ -250,9 +262,9 @@ static void simd_@TYPE@_@kind@_@STYPE@_@DTYPE@
* #VCHK = NPY_SIMD, NPY_SIMD_F64#
*/
/**begin repeat1
- * #kind = ceil, sqrt, absolute, square, reciprocal#
- * #intr = ceil, sqrt, abs, square, recip#
- * #clear = 0, 0, 1, 0, 0#
+ * #kind = rint, floor, ceil, trunc, sqrt, absolute, square, reciprocal#
+ * #intr = rint, floor, ceil, trunc, sqrt, abs, square, recip#
+ * #clear = 0, 0, 0, 0, 0, 1, 0, 0#
*/
NPY_NO_EXPORT void NPY_CPU_DISPATCH_CURFX(@TYPE@_@kind@)
(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func))
diff --git a/numpy/core/src/umath/simd.inc.src b/numpy/core/src/umath/simd.inc.src
index 8b833ee56..b477027b3 100644
--- a/numpy/core/src/umath/simd.inc.src
+++ b/numpy/core/src/umath/simd.inc.src
@@ -123,47 +123,6 @@ run_@func@_avx512_skx_@TYPE@(char **args, npy_intp const *dimensions, npy_intp c
/**end repeat**/
/**begin repeat
- * #ISA = FMA, AVX512F#
- * #isa = fma, avx512f#
- * #CHK = HAVE_ATTRIBUTE_TARGET_AVX2_WITH_INTRINSICS, HAVE_ATTRIBUTE_TARGET_AVX512F_WITH_INTRINSICS#
- * #REGISTER_SIZE = 32, 64#
- */
-
-/* prototypes */
-
-/**begin repeat1
- * #type = npy_float, npy_double#
- * #TYPE = FLOAT, DOUBLE#
- */
-
-/**begin repeat2
- * #func = rint, floor, trunc#
- */
-
-#if defined @CHK@ && defined NPY_HAVE_SSE2_INTRINSICS
-static NPY_INLINE NPY_GCC_TARGET_@ISA@ void
-@ISA@_@func@_@TYPE@(@type@ *, @type@ *, const npy_intp n, const npy_intp stride);
-#endif
-
-static NPY_INLINE int
-run_unary_@isa@_@func@_@TYPE@(char **args, npy_intp const *dimensions, npy_intp const *steps)
-{
-#if defined @CHK@ && defined NPY_HAVE_SSE2_INTRINSICS
- if (IS_OUTPUT_BLOCKABLE_UNARY(sizeof(@type@), sizeof(@type@), @REGISTER_SIZE@)) {
- @ISA@_@func@_@TYPE@((@type@*)args[1], (@type@*)args[0], dimensions[0], steps[0]);
- return 1;
- }
- else
- return 0;
-#endif
- return 0;
-}
-
-/**end repeat2**/
-/**end repeat1**/
-/**end repeat**/
-
-/**begin repeat
* Float types
* #type = npy_float, npy_double, npy_longdouble#
* #TYPE = FLOAT, DOUBLE, LONGDOUBLE#
@@ -1119,144 +1078,6 @@ AVX512_SKX_@func@_@TYPE@(npy_bool* op, @type@* ip, const npy_intp array_size, co
/**end repeat**/
/**begin repeat
- * #ISA = FMA, AVX512F#
- * #isa = fma, avx512#
- * #vsize = 256, 512#
- * #BYTES = 32, 64#
- * #cvtps_epi32 = _mm256_cvtps_epi32, #
- * #mask = __m256, __mmask16#
- * #vsub = , _mask#
- * #vtype = __m256, __m512#
- * #cvtps_epi32 = _mm256_cvtps_epi32, #
- * #masked_store = _mm256_maskstore_ps, _mm512_mask_storeu_ps#
- * #CHK = HAVE_ATTRIBUTE_TARGET_AVX2_WITH_INTRINSICS, HAVE_ATTRIBUTE_TARGET_AVX512F_WITH_INTRINSICS#
- */
-
-/**begin repeat1
- * #func = rint, floor, trunc#
- * #vectorf = rint, floor, trunc#
- */
-
-#if defined @CHK@
-static NPY_INLINE NPY_GCC_OPT_3 NPY_GCC_TARGET_@ISA@ void
-@ISA@_@func@_FLOAT(npy_float* op,
- npy_float* ip,
- const npy_intp array_size,
- const npy_intp steps)
-{
- const npy_intp stride = steps/(npy_intp)sizeof(npy_float);
- const npy_int num_lanes = @BYTES@/(npy_intp)sizeof(npy_float);
- npy_intp num_remaining_elements = array_size;
- @vtype@ ones_f = _mm@vsize@_set1_ps(1.0f);
- @mask@ load_mask = @isa@_get_full_load_mask_ps();
- /*
- * Note: while generally indices are npy_intp, we ensure that our maximum index
- * will fit in an int32 as a precondition for this function via
- * IS_OUTPUT_BLOCKABLE_UNARY
- */
-
- npy_int32 indexarr[16];
- for (npy_int32 ii = 0; ii < 16; ii++) {
- indexarr[ii] = ii*stride;
- }
- @vtype@i vindex = _mm@vsize@_loadu_si@vsize@((@vtype@i*)&indexarr[0]);
-
- while (num_remaining_elements > 0) {
- if (num_remaining_elements < num_lanes) {
- load_mask = @isa@_get_partial_load_mask_ps(num_remaining_elements,
- num_lanes);
- }
- @vtype@ x;
- if (stride == 1) {
- x = @isa@_masked_load_ps(load_mask, ip);
- }
- else {
- x = @isa@_masked_gather_ps(ones_f, ip, vindex, load_mask);
- }
- @vtype@ out = @isa@_@vectorf@_ps(x);
- @masked_store@(op, @cvtps_epi32@(load_mask), out);
-
- ip += num_lanes*stride;
- op += num_lanes;
- num_remaining_elements -= num_lanes;
- }
-}
-#endif
-/**end repeat1**/
-/**end repeat**/
-
-/**begin repeat
- * #ISA = FMA, AVX512F#
- * #isa = fma, avx512#
- * #vsize = 256, 512#
- * #BYTES = 32, 64#
- * #cvtps_epi32 = _mm256_cvtps_epi32, #
- * #mask = __m256i, __mmask8#
- * #vsub = , _mask#
- * #vtype = __m256d, __m512d#
- * #vindextype = __m128i, __m256i#
- * #vindexsize = 128, 256#
- * #vindexload = _mm_loadu_si128, _mm256_loadu_si256#
- * #cvtps_epi32 = _mm256_cvtpd_epi32, #
- * #castmask = _mm256_castsi256_pd, #
- * #masked_store = _mm256_maskstore_pd, _mm512_mask_storeu_pd#
- * #CHK = HAVE_ATTRIBUTE_TARGET_AVX2_WITH_INTRINSICS, HAVE_ATTRIBUTE_TARGET_AVX512F_WITH_INTRINSICS#
- */
-
-/**begin repeat1
- * #func = rint, floor, trunc#
- * #vectorf = rint, floor, trunc#
- */
-
-#if defined @CHK@
-static NPY_INLINE NPY_GCC_OPT_3 NPY_GCC_TARGET_@ISA@ void
-@ISA@_@func@_DOUBLE(npy_double* op,
- npy_double* ip,
- const npy_intp array_size,
- const npy_intp steps)
-{
- const npy_intp stride = steps/(npy_intp)sizeof(npy_double);
- const npy_int num_lanes = @BYTES@/(npy_intp)sizeof(npy_double);
- npy_intp num_remaining_elements = array_size;
- @mask@ load_mask = @isa@_get_full_load_mask_pd();
- @vtype@ ones_d = _mm@vsize@_set1_pd(1.0f);
-
- /*
- * Note: while generally indices are npy_intp, we ensure that our maximum index
- * will fit in an int32 as a precondition for this function via
- * IS_OUTPUT_BLOCKABLE_UNARY
- */
- npy_int32 indexarr[8];
- for (npy_int32 ii = 0; ii < 8; ii++) {
- indexarr[ii] = ii*stride;
- }
- @vindextype@ vindex = @vindexload@((@vindextype@*)&indexarr[0]);
-
- while (num_remaining_elements > 0) {
- if (num_remaining_elements < num_lanes) {
- load_mask = @isa@_get_partial_load_mask_pd(num_remaining_elements,
- num_lanes);
- }
- @vtype@ x;
- if (stride == 1) {
- x = @isa@_masked_load_pd(load_mask, ip);
- }
- else {
- x = @isa@_masked_gather_pd(ones_d, ip, vindex, @castmask@(load_mask));
- }
- @vtype@ out = @isa@_@vectorf@_pd(x);
- @masked_store@(op, load_mask, out);
-
- ip += num_lanes*stride;
- op += num_lanes;
- num_remaining_elements -= num_lanes;
- }
-}
-#endif
-/**end repeat1**/
-/**end repeat**/
-
-/**begin repeat
* #TYPE = CFLOAT, CDOUBLE#
* #type = npy_float, npy_double#
* #num_lanes = 16, 8#
@@ -1535,3 +1356,4 @@ sse2_@kind@_BOOL(@type@ * op, @type@ * ip, const npy_intp n)
#undef VECTOR_SIZE_BYTES
#endif /* NPY_HAVE_SSE2_INTRINSICS */
#endif
+
diff --git a/numpy/core/tests/test_cpu_features.py b/numpy/core/tests/test_cpu_features.py
index 706cf7a7e..1a76897e2 100644
--- a/numpy/core/tests/test_cpu_features.py
+++ b/numpy/core/tests/test_cpu_features.py
@@ -140,8 +140,8 @@ class Test_X86_Features(AbstractTest):
is_power = re.match("^(powerpc|ppc)64", machine, re.IGNORECASE)
@pytest.mark.skipif(not is_linux or not is_power, reason="Only for Linux and Power")
class Test_POWER_Features(AbstractTest):
- features = ["VSX", "VSX2", "VSX3"]
- features_map = dict(VSX2="ARCH_2_07", VSX3="ARCH_3_00")
+ features = ["VSX", "VSX2", "VSX3", "VSX4"]
+ features_map = dict(VSX2="ARCH_2_07", VSX3="ARCH_3_00", VSX4="ARCH_3_1")
def load_flags(self):
self.load_flags_auxv()
diff --git a/numpy/core/tests/test_simd.py b/numpy/core/tests/test_simd.py
index 12a67c44d..605baefe6 100644
--- a/numpy/core/tests/test_simd.py
+++ b/numpy/core/tests/test_simd.py
@@ -330,16 +330,18 @@ class _SIMD_FP(_Test_Utility):
square = self.square(vdata)
assert square == data_square
- @pytest.mark.parametrize("intrin, func", [("self.ceil", math.ceil),
- ("self.trunc", math.trunc)])
+ @pytest.mark.parametrize("intrin, func", [("ceil", math.ceil),
+ ("trunc", math.trunc), ("floor", math.floor), ("rint", round)])
def test_rounding(self, intrin, func):
"""
Test intrinsics:
+ npyv_rint_##SFX
npyv_ceil_##SFX
npyv_trunc_##SFX
+ npyv_floor##SFX
"""
intrin_name = intrin
- intrin = eval(intrin)
+ intrin = getattr(self, intrin)
pinf, ninf, nan = self._pinfinity(), self._ninfinity(), self._nan()
# special cases
round_cases = ((nan, nan), (pinf, pinf), (ninf, ninf))
@@ -347,20 +349,25 @@ class _SIMD_FP(_Test_Utility):
data_round = [desired]*self.nlanes
_round = intrin(self.setall(case))
assert _round == pytest.approx(data_round, nan_ok=True)
+
for x in range(0, 2**20, 256**2):
for w in (-1.05, -1.10, -1.15, 1.05, 1.10, 1.15):
- data = [x*w+a for a in range(self.nlanes)]
- vdata = self.load(data)
+ data = self.load([(x+a)*w for a in range(self.nlanes)])
data_round = [func(x) for x in data]
- _round = intrin(vdata)
+ _round = intrin(data)
assert _round == data_round
+
# signed zero
- if "ceil" in intrin_name or "trunc" in intrin_name:
- for w in (-0.25, -0.30, -0.45):
- _round = self._to_unsigned(intrin(self.setall(w)))
- data_round = self._to_unsigned(self.setall(-0.0))
- assert _round == data_round
-
+ if intrin_name == "floor":
+ data_szero = (-0.0,)
+ else:
+ data_szero = (-0.0, -0.25, -0.30, -0.45, -0.5)
+
+ for w in data_szero:
+ _round = self._to_unsigned(intrin(self.setall(w)))
+ data_round = self._to_unsigned(self.setall(-0.0))
+ assert _round == data_round
+
def test_max(self):
"""
Test intrinsics:
diff --git a/numpy/distutils/ccompiler_opt.py b/numpy/distutils/ccompiler_opt.py
index f1d024b94..854584998 100644
--- a/numpy/distutils/ccompiler_opt.py
+++ b/numpy/distutils/ccompiler_opt.py
@@ -294,6 +294,9 @@ class _Config:
VSX2 = dict(interest=2, implies="VSX", implies_detect=False),
## Power9/ISA 3.00
VSX3 = dict(interest=3, implies="VSX2", implies_detect=False),
+ ## Power10/ISA 3.1
+ VSX4 = dict(interest=4, implies="VSX3", implies_detect=False,
+ extra_checks="VSX4_MMA"),
# IBM/Z
## VX(z13) support
VX = dict(interest=1, headers="vecintrin.h"),
@@ -471,12 +474,16 @@ class _Config:
),
VSX3 = dict(
flags="-mcpu=power9 -mtune=power9", implies_detect=False
+ ),
+ VSX4 = dict(
+ flags="-mcpu=power10 -mtune=power10", implies_detect=False
)
)
if self.cc_is_clang:
partial["VSX"]["flags"] = "-maltivec -mvsx"
partial["VSX2"]["flags"] = "-mpower8-vector"
partial["VSX3"]["flags"] = "-mpower9-vector"
+ partial["VSX4"]["flags"] = "-mpower10-vector"
return partial
diff --git a/numpy/distutils/checks/cpu_vsx4.c b/numpy/distutils/checks/cpu_vsx4.c
new file mode 100644
index 000000000..a6acc7384
--- /dev/null
+++ b/numpy/distutils/checks/cpu_vsx4.c
@@ -0,0 +1,14 @@
+#ifndef __VSX__
+ #error "VSX is not supported"
+#endif
+#include <altivec.h>
+
+typedef __vector unsigned int v_uint32x4;
+
+int main(void)
+{
+ v_uint32x4 v1 = (v_uint32x4){2, 4, 8, 16};
+ v_uint32x4 v2 = (v_uint32x4){2, 2, 2, 2};
+ v_uint32x4 v3 = vec_mod(v1, v2);
+ return (int)vec_extractm(v3);
+}
diff --git a/numpy/distutils/checks/extra_vsx4_mma.c b/numpy/distutils/checks/extra_vsx4_mma.c
new file mode 100644
index 000000000..a70b2a9f6
--- /dev/null
+++ b/numpy/distutils/checks/extra_vsx4_mma.c
@@ -0,0 +1,21 @@
+#ifndef __VSX__
+ #error "VSX is not supported"
+#endif
+#include <altivec.h>
+
+typedef __vector float fv4sf_t;
+typedef __vector unsigned char vec_t;
+
+int main(void)
+{
+ __vector_quad acc0;
+ float a[4] = {0,1,2,3};
+ float b[4] = {0,1,2,3};
+ vec_t *va = (vec_t *) a;
+ vec_t *vb = (vec_t *) b;
+ __builtin_mma_xvf32ger(&acc0, va[0], vb[0]);
+ fv4sf_t result[4];
+ __builtin_mma_disassemble_acc((void *)result, &acc0);
+ fv4sf_t c0 = result[0];
+ return (int)((float*)&c0)[0];
+}
diff --git a/numpy/distutils/command/build.py b/numpy/distutils/command/build.py
index dc1ab3b9b..80830d559 100644
--- a/numpy/distutils/command/build.py
+++ b/numpy/distutils/command/build.py
@@ -47,8 +47,8 @@ class build(old_build):
- not part of dispatch-able features(--cpu-dispatch)
- not supported by compiler or platform
"""
- self.simd_test = "BASELINE SSE2 SSE42 XOP FMA4 (FMA3 AVX2) AVX512F" \
- " AVX512_SKX VSX VSX2 VSX3 NEON ASIMD VX VXE VXE2"
+ self.simd_test = "BASELINE SSE2 SSE42 XOP FMA4 (FMA3 AVX2) AVX512F " \
+ "AVX512_SKX VSX VSX2 VSX3 VSX4 NEON ASIMD VX VXE VXE2"
def finalize_options(self):
build_scripts = self.build_scripts
diff --git a/numpy/distutils/command/build_ext.py b/numpy/distutils/command/build_ext.py
index 7040a2411..36a62eb1a 100644
--- a/numpy/distutils/command/build_ext.py
+++ b/numpy/distutils/command/build_ext.py
@@ -231,20 +231,36 @@ class build_ext (old_build_ext):
l = ext.language or self.compiler.detect_language(ext.sources)
if l:
ext_languages.add(l)
+
# reset language attribute for choosing proper linker
+ #
+ # When we build extensions with multiple languages, we have to
+ # choose a linker. The rules here are:
+ # 1. if there is Fortran code, always prefer the Fortran linker,
+ # 2. otherwise prefer C++ over C,
+ # 3. Users can force a particular linker by using
+ # `language='c'` # or 'c++', 'f90', 'f77'
+ # in their config.add_extension() calls.
if 'c++' in ext_languages:
ext_language = 'c++'
- elif 'f90' in ext_languages:
+ else:
+ ext_language = 'c' # default
+
+ has_fortran = False
+ if 'f90' in ext_languages:
ext_language = 'f90'
+ has_fortran = True
elif 'f77' in ext_languages:
ext_language = 'f77'
- else:
- ext_language = 'c' # default
- if l and l != ext_language and ext.language:
- log.warn('resetting extension %r language from %r to %r.' %
- (ext.name, l, ext_language))
- if not ext.language:
+ has_fortran = True
+
+ if not ext.language or has_fortran:
+ if l and l != ext_language and ext.language:
+ log.warn('resetting extension %r language from %r to %r.' %
+ (ext.name, l, ext_language))
+
ext.language = ext_language
+
# global language
all_languages.update(ext_languages)
diff --git a/numpy/distutils/tests/test_ccompiler_opt.py b/numpy/distutils/tests/test_ccompiler_opt.py
index 6f9970c75..1ca8bc09b 100644
--- a/numpy/distutils/tests/test_ccompiler_opt.py
+++ b/numpy/distutils/tests/test_ccompiler_opt.py
@@ -405,7 +405,7 @@ class _Test_CCompilerOpt:
# in msvc, avx512_knl avx512_knm aren't supported
x86_msvc=".* xop fma4 .* avx512f .* avx512_skx .*",
armhf=".* asimd asimdhp asimddp .*",
- ppc64="vsx vsx2 vsx3.*",
+ ppc64="vsx vsx2 vsx3 vsx4.*",
s390x="vx vxe vxe2.*"
)
# min
@@ -544,13 +544,13 @@ class _Test_CCompilerOpt:
"""
/*@targets
sse sse2 sse41 avx avx2 avx512f
- vsx vsx2 vsx3
+ vsx vsx2 vsx3 vsx4
neon neon_fp16 asimdhp asimddp
vx vxe vxe2
*/
""",
baseline="avx vsx2 asimd vx vxe",
- x86="avx512f avx2", armhf="asimddp asimdhp", ppc64="vsx3",
+ x86="avx512f avx2", armhf="asimddp asimdhp", ppc64="vsx4 vsx3",
s390x="vxe2"
)
# test skipping non-dispatch features
@@ -558,7 +558,7 @@ class _Test_CCompilerOpt:
"""
/*@targets
sse41 avx avx2 avx512f
- vsx2 vsx3
+ vsx2 vsx3 vsx4
asimd asimdhp asimddp
vx vxe vxe2
*/
@@ -571,13 +571,13 @@ class _Test_CCompilerOpt:
"""
/*@targets
sse2 sse41 avx2 avx512f
- vsx2 vsx3
+ vsx2 vsx3 vsx4
neon asimdhp asimddp
vx vxe vxe2
*/
""",
baseline="",
- trap_files=".*(avx2|avx512f|vsx3|asimddp|vxe2).c",
+ trap_files=".*(avx2|avx512f|vsx3|vsx4|asimddp|vxe2).c",
x86="sse41 sse2", ppc64="vsx2", armhf="asimdhp neon",
s390x="vxe vx"
)
diff --git a/numpy/f2py/capi_maps.py b/numpy/f2py/capi_maps.py
index 581f946e5..b4fab71f9 100644
--- a/numpy/f2py/capi_maps.py
+++ b/numpy/f2py/capi_maps.py
@@ -504,7 +504,8 @@ def sign2map(a, var):
varname,ctype,atype
init,init.r,init.i,pytype
vardebuginfo,vardebugshowvalue,varshowvalue
- varrfromat
+ varrformat
+
intent
"""
out_a = a
diff --git a/numpy/f2py/cfuncs.py b/numpy/f2py/cfuncs.py
index 528c4adee..bdd27adaf 100644
--- a/numpy/f2py/cfuncs.py
+++ b/numpy/f2py/cfuncs.py
@@ -572,18 +572,20 @@ cppmacros['OLDPYNUM'] = """\
"""
cppmacros["F2PY_THREAD_LOCAL_DECL"] = """\
#ifndef F2PY_THREAD_LOCAL_DECL
-#if defined(_MSC_VER) \\
- || defined(_WIN32) || defined(_WIN64) \\
- || defined(__MINGW32__) || defined(__MINGW64__)
+#if defined(_MSC_VER)
#define F2PY_THREAD_LOCAL_DECL __declspec(thread)
+#elif defined(__MINGW32__) || defined(__MINGW64__)
+#define F2PY_THREAD_LOCAL_DECL __thread
#elif defined(__STDC_VERSION__) \\
&& (__STDC_VERSION__ >= 201112L) \\
&& !defined(__STDC_NO_THREADS__) \\
- && (!defined(__GLIBC__) || __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 12))
+ && (!defined(__GLIBC__) || __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 12)) \\
+ && !defined(__OpenBSD__)
/* __STDC_NO_THREADS__ was first defined in a maintenance release of glibc 2.12,
see https://lists.gnu.org/archive/html/commit-hurd/2012-07/msg00180.html,
so `!defined(__STDC_NO_THREADS__)` may give false positive for the existence
- of `threads.h` when using an older release of glibc 2.12 */
+ of `threads.h` when using an older release of glibc 2.12
+ See gh-19437 for details on OpenBSD */
#include <threads.h>
#define F2PY_THREAD_LOCAL_DECL thread_local
#elif defined(__GNUC__) \\
diff --git a/numpy/f2py/crackfortran.py b/numpy/f2py/crackfortran.py
index aacd2c676..0374ae8d7 100755
--- a/numpy/f2py/crackfortran.py
+++ b/numpy/f2py/crackfortran.py
@@ -892,6 +892,9 @@ def appenddecl(decl, decl2, force=1):
selectpattern = re.compile(
r'\s*(?P<this>(@\(@.*?@\)@|\*[\d*]+|\*\s*@\(@.*?@\)@|))(?P<after>.*)\Z', re.I)
+typedefpattern = re.compile(
+ r'(?:,(?P<attributes>[\w(),]+))?(::)?(?P<name>\b[a-z$_][\w$]*\b)'
+ r'(?:\((?P<params>[\w,]*)\))?\Z', re.I)
nameargspattern = re.compile(
r'\s*(?P<name>\b[\w$]+\b)\s*(@\(@\s*(?P<args>[\w\s,]*)\s*@\)@|)\s*((result(\s*@\(@\s*(?P<result>\b[\w$]+\b)\s*@\)@|))|(bind\s*@\(@\s*(?P<bind>.*)\s*@\)@))*\s*\Z', re.I)
operatorpattern = re.compile(
@@ -914,6 +917,17 @@ def _is_intent_callback(vdecl):
return 0
+def _resolvetypedefpattern(line):
+ line = ''.join(line.split()) # removes whitespace
+ m1 = typedefpattern.match(line)
+ print(line, m1)
+ if m1:
+ attrs = m1.group('attributes')
+ attrs = [a.lower() for a in attrs.split(',')] if attrs else []
+ return m1.group('name'), attrs, m1.group('params')
+ return None, [], None
+
+
def _resolvenameargspattern(line):
line = markouterparen(line)
m1 = nameargspattern.match(line)
@@ -962,7 +976,13 @@ def analyzeline(m, case, line):
block = 'python module'
elif re.match(r'abstract\s*interface', block, re.I):
block = 'abstract interface'
- name, args, result, bind = _resolvenameargspattern(m.group('after'))
+ if block == 'type':
+ name, attrs, _ = _resolvetypedefpattern(m.group('after'))
+ groupcache[groupcounter]['vars'][name] = dict(attrspec = attrs)
+ args = []
+ result = None
+ else:
+ name, args, result, _ = _resolvenameargspattern(m.group('after'))
if name is None:
if block == 'block data':
name = '_BLOCK_DATA_'
diff --git a/numpy/f2py/tests/src/crackfortran/accesstype.f90 b/numpy/f2py/tests/src/crackfortran/accesstype.f90
new file mode 100644
index 000000000..e2cbd445d
--- /dev/null
+++ b/numpy/f2py/tests/src/crackfortran/accesstype.f90
@@ -0,0 +1,13 @@
+module foo
+ public
+ type, private, bind(c) :: a
+ integer :: i
+ end type a
+ type, bind(c) :: b_
+ integer :: j
+ end type b_
+ public :: b_
+ type :: c
+ integer :: k
+ end type c
+end module foo
diff --git a/numpy/f2py/tests/test_crackfortran.py b/numpy/f2py/tests/test_crackfortran.py
index e33e12d62..ea618bf33 100644
--- a/numpy/f2py/tests/test_crackfortran.py
+++ b/numpy/f2py/tests/test_crackfortran.py
@@ -44,6 +44,15 @@ class TestPublicPrivate:
assert "private" not in mod["vars"]["seta"]["attrspec"]
assert "public" in mod["vars"]["seta"]["attrspec"]
+ def test_access_type(self, tmp_path):
+ fpath = util.getpath("tests", "src", "crackfortran", "accesstype.f90")
+ mod = crackfortran.crackfortran([str(fpath)])
+ assert len(mod) == 1
+ tt = mod[0]['vars']
+ assert set(tt['a']['attrspec']) == {'private', 'bind(c)'}
+ assert set(tt['b_']['attrspec']) == {'public', 'bind(c)'}
+ assert set(tt['c']['attrspec']) == {'public'}
+
class TestModuleProcedure():
def test_moduleOperators(self, tmp_path):
diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py
index d4abde425..d5b130b72 100644
--- a/numpy/lib/function_base.py
+++ b/numpy/lib/function_base.py
@@ -4907,7 +4907,7 @@ def meshgrid(*xi, copy=True, sparse=False, indexing='xy'):
>>> x = np.linspace(-5, 5, 101)
>>> y = np.linspace(-5, 5, 101)
- >>> # full coorindate arrays
+ >>> # full coordinate arrays
>>> xx, yy = np.meshgrid(x, y)
>>> zz = np.sqrt(xx**2 + yy**2)
>>> xx.shape, yy.shape, zz.shape
diff --git a/numpy/lib/polynomial.py b/numpy/lib/polynomial.py
index f824c4c5e..6aa708861 100644
--- a/numpy/lib/polynomial.py
+++ b/numpy/lib/polynomial.py
@@ -686,7 +686,7 @@ def polyfit(x, y, deg, rcond=None, full=False, w=None, cov=False):
"to scale the covariance matrix")
# note, this used to be: fac = resids / (len(x) - order - 2.0)
# it was deciced that the "- 2" (originally justified by "Bayesian
- # uncertainty analysis") is not was the user expects
+ # uncertainty analysis") is not what the user expects
# (see gh-11196 and gh-11197)
fac = resids / (len(x) - order)
if y.ndim == 1:
diff --git a/numpy/ma/core.py b/numpy/ma/core.py
index e0e5403a9..9c9dfac68 100644
--- a/numpy/ma/core.py
+++ b/numpy/ma/core.py
@@ -3542,15 +3542,17 @@ class MaskedArray(ndarray):
def harden_mask(self):
"""
- Force the mask to hard.
+ Force the mask to hard, preventing unmasking by assignment.
Whether the mask of a masked array is hard or soft is determined by
its `~ma.MaskedArray.hardmask` property. `harden_mask` sets
- `~ma.MaskedArray.hardmask` to ``True``.
+ `~ma.MaskedArray.hardmask` to ``True`` (and returns the modified
+ self).
See Also
--------
ma.MaskedArray.hardmask
+ ma.MaskedArray.soften_mask
"""
self._hardmask = True
@@ -3558,15 +3560,17 @@ class MaskedArray(ndarray):
def soften_mask(self):
"""
- Force the mask to soft.
+ Force the mask to soft (default), allowing unmasking by assignment.
Whether the mask of a masked array is hard or soft is determined by
its `~ma.MaskedArray.hardmask` property. `soften_mask` sets
- `~ma.MaskedArray.hardmask` to ``False``.
+ `~ma.MaskedArray.hardmask` to ``False`` (and returns the modified
+ self).
See Also
--------
ma.MaskedArray.hardmask
+ ma.MaskedArray.harden_mask
"""
self._hardmask = False
@@ -3574,16 +3578,55 @@ class MaskedArray(ndarray):
@property
def hardmask(self):
- """ Hardness of the mask """
+ """
+ Specifies whether values can be unmasked through assignments.
+
+ By default, assigning definite values to masked array entries will
+ unmask them. When `hardmask` is ``True``, the mask will not change
+ through assignments.
+
+ See Also
+ --------
+ ma.MaskedArray.harden_mask
+ ma.MaskedArray.soften_mask
+
+ Examples
+ --------
+ >>> x = np.arange(10)
+ >>> m = np.ma.masked_array(x, x>5)
+ >>> assert not m.hardmask
+
+ Since `m` has a soft mask, assigning an element value unmasks that
+ element:
+
+ >>> m[8] = 42
+ >>> m
+ masked_array(data=[0, 1, 2, 3, 4, 5, --, --, 42, --],
+ mask=[False, False, False, False, False, False,
+ True, True, False, True],
+ fill_value=999999)
+
+ After hardening, the mask is not affected by assignments:
+
+ >>> hardened = np.ma.harden_mask(m)
+ >>> assert m.hardmask and hardened is m
+ >>> m[:] = 23
+ >>> m
+ masked_array(data=[23, 23, 23, 23, 23, 23, --, --, 23, --],
+ mask=[False, False, False, False, False, False,
+ True, True, False, True],
+ fill_value=999999)
+
+ """
return self._hardmask
def unshare_mask(self):
"""
- Copy the mask and set the sharedmask flag to False.
+ Copy the mask and set the `sharedmask` flag to ``False``.
Whether the mask is shared between masked arrays can be seen from
- the `sharedmask` property. `unshare_mask` ensures the mask is not shared.
- A copy of the mask is only made if it was shared.
+ the `sharedmask` property. `unshare_mask` ensures the mask is not
+ shared. A copy of the mask is only made if it was shared.
See Also
--------
diff --git a/numpy/random/mtrand.pyx b/numpy/random/mtrand.pyx
index 8bf74aa5d..38b5484bc 100644
--- a/numpy/random/mtrand.pyx
+++ b/numpy/random/mtrand.pyx
@@ -4341,7 +4341,7 @@ cdef class RandomState:
The drawn samples, of shape ``(size, k)``.
Raises
- -------
+ ------
ValueError
If any value in ``alpha`` is less than or equal to zero
diff --git a/numpy/setup.py b/numpy/setup.py
index a0ca99919..ebad66122 100644
--- a/numpy/setup.py
+++ b/numpy/setup.py
@@ -23,6 +23,7 @@ def configuration(parent_package='',top_path=None):
config.add_data_files('py.typed')
config.add_data_files('*.pyi')
config.add_subpackage('tests')
+ config.add_subpackage('_pyinstaller')
config.make_config_py() # installs __config__.py
return config
diff --git a/numpy/testing/_private/extbuild.py b/numpy/testing/_private/extbuild.py
index 940e2f7d7..b7a071e7f 100644
--- a/numpy/testing/_private/extbuild.py
+++ b/numpy/testing/_private/extbuild.py
@@ -8,8 +8,6 @@ import os
import pathlib
import sys
import sysconfig
-from numpy.distutils.ccompiler import new_compiler
-from distutils.errors import CompileError
__all__ = ['build_and_import_extension', 'compile_extension_module']
@@ -53,6 +51,7 @@ def build_and_import_extension(
>>> assert not mod.test_bytes(u'abc')
>>> assert mod.test_bytes(b'abc')
"""
+ from distutils.errors import CompileError
body = prologue + _make_methods(functions, modname)
init = """PyObject *mod = PyModule_Create(&moduledef);
@@ -221,6 +220,7 @@ def _c_compile(cfile, outputfilename, include_dirs=[], libraries=[],
def build(cfile, outputfilename, compile_extra, link_extra,
include_dirs, libraries, library_dirs):
"cd into the directory where the cfile is, use distutils to build"
+ from numpy.distutils.ccompiler import new_compiler
compiler = new_compiler(force=1, verbose=2)
compiler.customize('')
diff --git a/numpy/typing/tests/data/reveal/lib_function_base.pyi b/numpy/typing/tests/data/reveal/lib_function_base.pyi
index c559eb295..eebe9fbfd 100644
--- a/numpy/typing/tests/data/reveal/lib_function_base.pyi
+++ b/numpy/typing/tests/data/reveal/lib_function_base.pyi
@@ -26,7 +26,7 @@ reveal_type(vectorized_func.signature) # E: Union[None, builtins.str]
reveal_type(vectorized_func.otypes) # E: Union[None, builtins.str]
reveal_type(vectorized_func.excluded) # E: set[Union[builtins.int, builtins.str]]
reveal_type(vectorized_func.__doc__) # E: Union[None, builtins.str]
-reveal_type(vectorized_func([1])) # E: ndarray[Any, dtype[Any]]
+reveal_type(vectorized_func([1])) # E: Any
reveal_type(np.vectorize(int)) # E: vectorize
reveal_type(np.vectorize( # E: vectorize
int, otypes="i", doc="doc", excluded=(), cache=True, signature=None
diff --git a/setup.py b/setup.py
index bfb40acf1..c520ed69e 100755
--- a/setup.py
+++ b/setup.py
@@ -291,7 +291,7 @@ def parse_setuppy_commands():
- `pip install .` (from a git repo or downloaded source
release)
- - `pip install numpy` (last NumPy release on PyPi)
+ - `pip install numpy` (last NumPy release on PyPI)
"""))
return True
@@ -303,7 +303,7 @@ def parse_setuppy_commands():
To install NumPy from here with reliable uninstall, we recommend
that you use `pip install .`. To install the latest NumPy release
- from PyPi, use `pip install numpy`.
+ from PyPI, use `pip install numpy`.
For help with build/installation issues, please ask on the
numpy-discussion mailing list. If you are sure that you have run
@@ -371,7 +371,7 @@ def get_docs_url():
if 'dev' in VERSION:
return "https://numpy.org/devdocs"
else:
- # For releases, this URL ends up on pypi.
+ # For releases, this URL ends up on PyPI.
# By pinning the version, users looking at old PyPI releases can get
# to the associated docs easily.
return "https://numpy.org/doc/{}.{}".format(MAJOR, MINOR)
@@ -421,6 +421,7 @@ def setup_package():
entry_points={
'console_scripts': f2py_cmds,
'array_api': ['numpy = numpy.array_api'],
+ 'pyinstaller40': ['hook-dirs = numpy:_pyinstaller_hooks_dir'],
},
)
diff --git a/tools/gitpod/Dockerfile b/tools/gitpod/Dockerfile
index e2e0e1bc9..592a5ee0a 100644
--- a/tools/gitpod/Dockerfile
+++ b/tools/gitpod/Dockerfile
@@ -27,7 +27,7 @@
# OS/ARCH: linux/amd64
FROM gitpod/workspace-base:latest
-ARG MAMBAFORGE_VERSION="4.10.0-0"
+ARG MAMBAFORGE_VERSION="4.11.0-0"
ARG CONDA_ENV=numpy-dev
diff --git a/tools/openblas_support.py b/tools/openblas_support.py
index 4eb72dbc9..c89cb9284 100644
--- a/tools/openblas_support.py
+++ b/tools/openblas_support.py
@@ -13,8 +13,9 @@ from tempfile import mkstemp, gettempdir
from urllib.request import urlopen, Request
from urllib.error import HTTPError
-OPENBLAS_V = '0.3.18'
-OPENBLAS_LONG = 'v0.3.18'
+# 0.3.19 fails AVX512_SKX tests, issue 20654, comments in PR 20660
+OPENBLAS_V = '0.3.19.dev'
+OPENBLAS_LONG = 'v0.3.19-22-g5188aede'
BASE_LOC = 'https://anaconda.org/multibuild-wheels-staging/openblas-libs'
BASEURL = f'{BASE_LOC}/{OPENBLAS_LONG}/download'
SUPPORTED_PLATFORMS = [
diff --git a/tools/travis-test.sh b/tools/travis-test.sh
index b395942fb..db5b3f744 100755
--- a/tools/travis-test.sh
+++ b/tools/travis-test.sh
@@ -83,7 +83,7 @@ run_test()
# in test_requirements.txt) does not provide a wheel, and the source tar
# file does not install correctly when Python's optimization level is set
# to strip docstrings (see https://github.com/eliben/pycparser/issues/291).
- PYTHONOPTIMIZE="" $PIP install -r test_requirements.txt
+ PYTHONOPTIMIZE="" $PIP install -r test_requirements.txt pyinstaller
DURATIONS_FLAG="--durations 10"
if [ -n "$USE_DEBUG" ]; then