Skip to content

Commit 295009d

Browse files
MAINT: Convert the 'first' module to C++. Require C++17.
1 parent d33e88c commit 295009d

9 files changed

+474
-517
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ installing, run
1414

1515
pytest --pyargs ufunclab
1616

17-
To build `ufunclab`, a C99-compatible C compiler and a C++14-compatible C++
17+
To build `ufunclab`, a C99-compatible C compiler and a C++17-compatible C++
1818
compiler are required.
1919

2020
The unit tests require [pytest](https://docs.pytest.org/).

meson.build

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ project(
55
meson_version: '>= 1.1.0',
66
default_options: [
77
'c_std=c99',
8-
'cpp_std=c++14',
8+
'cpp_std=c++17',
99
],
1010
)
1111

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ requires = [
88

99
[project]
1010
name = 'ufunclab'
11-
version = '0.0.8.dev12'
11+
version = '0.0.8.dev13'
1212
description = 'NumPy ufuncs and utilities.'
1313
readme = 'README.md'
1414
requires-python = '>=3.9'

src/first/define_cxx_gufunc_extmod.py

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
2+
from ufunc_config_types import UFuncExtMod, UFunc, UFuncSource
3+
4+
5+
FIRST_DOCSTRING = """\
6+
first(x, op, target, otherwise, /, ...)
7+
8+
Find the first value that matches the given comparison.
9+
"""
10+
11+
ARGFIRST_DOCSTRING = """\
12+
argfirst(x, op, target, /, ...)
13+
14+
Find the index in `x` of the first value where `x op target`
15+
is true, where `op` is one of the basic comparison operators.
16+
17+
Parameters
18+
----------
19+
x : array_like, size (..., n)
20+
Array to be searched.
21+
op : int, one of {0, 1, 2, 3, 4, 5}
22+
Defines the comparison operation to be used. Attributes of
23+
the class `ufunclab.op` may be used as symbolic names of
24+
the operators.
25+
26+
Comparison op ufunclab.op attribute
27+
---------- -- ---------------------
28+
< 0 ufunclab.op.LT
29+
<= 1 ufunclab.op.LE
30+
== 2 ufunclab.op.EQ
31+
!= 3 ufunclab.op.NE
32+
> 4 ufunclab.op.GT
33+
>= 5 ufunclab.op.GE
34+
35+
An error is not raised if `op` is not in {0, 1, 2, 3, 4, 5},
36+
but the return value will be -1.
37+
38+
target : value to be searched for
39+
For best efficiency, this value should have the same
40+
type as the elements of `x`.
41+
42+
Returns
43+
-------
44+
index : integer
45+
The index of the first element where the comparison
46+
is true. If no value is found, -1 is returned.
47+
48+
Examples
49+
--------
50+
>>> import numpy as np
51+
>>> from ufunclab import argfirst, op
52+
53+
Find the index of the first occurrence of 0 in `x`:
54+
55+
>>> x = np.array([10, 35, 19, 0, -1, 24, 0])
56+
>>> argfirst(x, op.EQ, 0)
57+
3
58+
59+
Find the index of the first nonzero value in `a`:
60+
61+
>>> a = np.array([0, 0, 0, 0, 0, -0.5, 0, 1, 0.1])
62+
>>> argfirst(a, op.NE, 0.0)
63+
5
64+
65+
`argfirst` is a gufunc, so it can handle higher-dimensional
66+
array arguments, and among its gufunc-related parameters is
67+
`axis`. By default, the gufunc operates along the last axis.
68+
For example, here we find the location of the first nonzero
69+
element in each row of `b`:
70+
71+
>>> b = np.array([[0, 8, 0, 0], [0, 0, 0, 0], [0, 0, 9, 2]],
72+
... dtype=np.uint8)
73+
>>> b
74+
array([[0, 8, 0, 0],
75+
[0, 0, 0, 0],
76+
[0, 0, 9, 2]])
77+
>>> argfirst(b, op.NE, np.uint8(0))
78+
array([ 1, -1, 2])
79+
80+
If we give the argument `axis=0`, we tell `argfirst` to
81+
operate along the first axis, which in this case is the
82+
columns:
83+
84+
>>> argfirst(b, op.NE, np.uint8(0), axis=0)
85+
array([-1, 0, 2, 2])
86+
87+
"""
88+
89+
first_src = UFuncSource(
90+
funcname='first_core_calc',
91+
typesignatures=[
92+
'bbbb->b',
93+
'BbBB->B',
94+
'hbhh->h',
95+
'HbHH->H',
96+
'ibii->i',
97+
'IbII->I',
98+
'lbll->l',
99+
'LbLL->L',
100+
'fbff->f',
101+
'dbdd->d',
102+
'gbgg->g',
103+
]
104+
)
105+
106+
first_src_object = UFuncSource(
107+
funcname='first_core_calc_object',
108+
typesignatures=['ObOO->O']
109+
)
110+
111+
first = UFunc(
112+
name='first',
113+
header='first_gufunc.h',
114+
docstring=FIRST_DOCSTRING,
115+
signature='(n),(),(),()->()',
116+
sources=[first_src, first_src_object],
117+
)
118+
119+
argfirst_src = UFuncSource(
120+
funcname='argfirst_core_calc',
121+
typesignatures=[
122+
'bbb->l',
123+
'BbB->l',
124+
'hbh->l',
125+
'HbH->l',
126+
'ibi->l',
127+
'IbI->l',
128+
'lbl->l',
129+
'LbL->l',
130+
'fbf->l',
131+
'dbd->l',
132+
'gbg->l',
133+
]
134+
)
135+
136+
argfirst_src_object = UFuncSource(
137+
funcname='argfirst_core_calc_object',
138+
typesignatures=['ObO->l']
139+
)
140+
141+
argfirst = UFunc(
142+
name='argfirst',
143+
header='first_gufunc.h',
144+
docstring=ARGFIRST_DOCSTRING,
145+
signature='(n),(),()->()',
146+
sources=[argfirst_src, argfirst_src_object],
147+
)
148+
149+
extmod = UFuncExtMod(
150+
module='_first',
151+
docstring=("This extension module defines the gufuncs 'first' and "
152+
"'argfirst'."),
153+
ufuncs=[first, argfirst],
154+
# The call `status = add_comparison_constants(module);` will be
155+
# added to the end of the module init function.
156+
extra_module_funcs=['add_comparison_constants']
157+
)

0 commit comments

Comments
 (0)