Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cython
Commits
99b874cb
Commit
99b874cb
authored
Nov 18, 2020
by
Stefan Behnel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Optimise calling float() on bytes/bytearray values by returning a C double directly.
parent
2d200b1c
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
106 additions
and
10 deletions
+106
-10
CHANGES.rst
CHANGES.rst
+2
-0
Cython/Compiler/Optimize.py
Cython/Compiler/Optimize.py
+15
-3
Cython/Utility/Optimize.c
Cython/Utility/Optimize.c
+57
-7
tests/run/builtin_float.py
tests/run/builtin_float.py
+32
-0
No files found.
CHANGES.rst
View file @
99b874cb
...
...
@@ -21,6 +21,8 @@ Features added
also
when
compiled
by
Cython
.
Patch
by
Pedro
Marques
da
Luz
.
(
Github
issue
#
2273
)
*
``
float
(
…
)``
is
optimised
for
``
bytes
``
and
``
bytearray
``
arguments
.
*
Docstrings
of
``
cpdef
``
enums
are
now
copied
to
the
enum
class
.
Patch
by
matham
.
(
Github
issue
#
3805
)
...
...
Cython/Compiler/Optimize.py
View file @
99b874cb
...
...
@@ -2189,7 +2189,7 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
func_arg
=
arg
.
args
[
0
]
if
func_arg
.
type
is
Builtin
.
float_type
:
return
func_arg
.
as_none_safe_node
(
"float() argument must be a string or a number, not 'NoneType'"
)
elif
func_arg
.
type
.
is_pyobject
:
elif
func_arg
.
type
.
is_pyobject
and
arg
.
function
.
cname
==
"__Pyx__PyObject_AsDouble"
:
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
'__Pyx_PyNumber_Float'
,
self
.
PyNumber_Float_func_type
,
args
=
[
func_arg
],
...
...
@@ -2619,6 +2619,7 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
elif
len
(
pos_args
)
!=
1
:
self
.
_error_wrong_arg_count
(
'float'
,
node
,
pos_args
,
'0 or 1'
)
return
node
func_arg
=
pos_args
[
0
]
if
isinstance
(
func_arg
,
ExprNodes
.
CoerceToPyTypeNode
):
func_arg
=
func_arg
.
arg
...
...
@@ -2627,12 +2628,23 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
elif
node
.
type
.
assignable_from
(
func_arg
.
type
)
or
func_arg
.
type
.
is_numeric
:
return
ExprNodes
.
TypecastNode
(
node
.
pos
,
operand
=
func_arg
,
type
=
node
.
type
)
if
func_arg
.
type
is
Builtin
.
bytes_type
:
cfunc_name
=
"__Pyx_PyBytes_AsDouble"
utility_code_name
=
'pybytes_as_double'
elif
func_arg
.
type
is
Builtin
.
bytearray_type
:
cfunc_name
=
"__Pyx_PyByteArray_AsDouble"
utility_code_name
=
'pybytes_as_double'
else
:
cfunc_name
=
"__Pyx_PyObject_AsDouble"
utility_code_name
=
'pyobject_as_double'
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
"__Pyx_PyObject_AsDouble"
,
node
.
pos
,
cfunc_name
,
self
.
PyObject_AsDouble_func_type
,
args
=
pos_args
,
is_temp
=
node
.
is_temp
,
utility_code
=
load_c_utility
(
'pyobject_as_double'
),
utility_code
=
load_c_utility
(
utility_code_name
),
py_name
=
"float"
)
PyNumber_Int_func_type
=
PyrexTypes
.
CFuncType
(
...
...
Cython/Utility/Optimize.c
View file @
99b874cb
...
...
@@ -596,6 +596,7 @@ static double __Pyx__PyObject_AsDouble(PyObject* obj); /* proto */
#endif
/////////////// pyobject_as_double ///////////////
//@requires: pybytes_as_double
//@requires: ObjectHandling.c::PyObjectCallOneArg
static
double
__Pyx__PyObject_AsDouble
(
PyObject
*
obj
)
{
...
...
@@ -604,9 +605,20 @@ static double __Pyx__PyObject_AsDouble(PyObject* obj) {
float_value
=
PyNumber_Float
(
obj
);
if
((
0
))
goto
bad
;
// avoid "unused" warnings
(
void
)
__Pyx_PyObject_CallOneArg
;
(
void
)
__Pyx__PyBytes_AsDouble
;
#else
PyNumberMethods
*
nb
=
Py_TYPE
(
obj
)
->
tp_as_number
;
if
(
likely
(
nb
)
&&
likely
(
nb
->
nb_float
))
{
if
(
PyBytes_CheckExact
(
obj
))
{
return
__Pyx_PyBytes_AsDouble
(
obj
);
}
else
if
(
PyByteArray_CheckExact
(
obj
))
{
return
__Pyx_PyByteArray_AsDouble
(
obj
);
}
else
if
(
PyUnicode_CheckExact
(
obj
))
{
#if PY_MAJOR_VERSION >= 3
float_value
=
PyFloat_FromString
(
obj
);
#else
float_value
=
PyFloat_FromString
(
obj
,
0
);
#endif
}
else
if
(
likely
(
nb
)
&&
likely
(
nb
->
nb_float
))
{
float_value
=
nb
->
nb_float
(
obj
);
if
(
likely
(
float_value
)
&&
unlikely
(
!
PyFloat_Check
(
float_value
)))
{
__Pyx_TypeName
float_value_type_name
=
__Pyx_PyType_GetName
(
Py_TYPE
(
float_value
));
...
...
@@ -617,12 +629,6 @@ static double __Pyx__PyObject_AsDouble(PyObject* obj) {
Py_DECREF
(
float_value
);
goto
bad
;
}
}
else
if
(
PyUnicode_CheckExact
(
obj
)
||
PyBytes_CheckExact
(
obj
))
{
#if PY_MAJOR_VERSION >= 3
float_value
=
PyFloat_FromString
(
obj
);
#else
float_value
=
PyFloat_FromString
(
obj
,
0
);
#endif
}
else
{
float_value
=
__Pyx_PyObject_CallOneArg
((
PyObject
*
)
&
PyFloat_Type
,
obj
);
}
...
...
@@ -637,6 +643,50 @@ bad:
}
/////////////// pybytes_as_double.proto ///////////////
static
double
__Pyx__PyBytes_AsDouble
(
PyObject
*
obj
,
const
char
*
start
,
Py_ssize_t
length
);
/*proto*/
static
CYTHON_INLINE
double
__Pyx_PyBytes_AsDouble
(
PyObject
*
obj
)
{
return
__Pyx__PyBytes_AsDouble
(
obj
,
PyBytes_AS_STRING
(
obj
),
PyBytes_GET_SIZE
(
obj
));
}
static
CYTHON_INLINE
double
__Pyx_PyByteArray_AsDouble
(
PyObject
*
obj
)
{
return
__Pyx__PyBytes_AsDouble
(
obj
,
PyByteArray_AS_STRING
(
obj
),
PyByteArray_GET_SIZE
(
obj
));
}
/////////////// pybytes_as_double ///////////////
static
double
__Pyx__PyBytes_AsDouble
(
PyObject
*
bytes
,
const
char
*
start
,
Py_ssize_t
length
)
{
PyObject
*
float_value
;
if
(
likely
(
!
memchr
(
start
,
'_'
,
length
)))
{
const
char
*
end
,
*
last
=
start
+
length
;
double
value
;
while
(
Py_ISSPACE
(
*
start
))
start
++
;
while
(
start
<
last
-
1
&&
Py_ISSPACE
(
last
[
-
1
]))
last
--
;
value
=
PyOS_string_to_double
(
start
,
(
char
**
)
&
end
,
NULL
);
if
(
likely
(
end
==
last
)
||
(
value
==
(
double
)
-
1
&&
PyErr_Occurred
()))
{
return
value
;
}
}
// slow fallback
#if PY_MAJOR_VERSION >= 3
float_value
=
PyFloat_FromString
(
bytes
);
#else
float_value
=
PyFloat_FromString
(
bytes
,
0
);
#endif
if
(
likely
(
float_value
))
{
double
value
=
PyFloat_AS_DOUBLE
(
float_value
);
Py_DECREF
(
float_value
);
return
value
;
}
bad:
return
(
double
)
-
1
;
}
/////////////// PyNumberPow2.proto ///////////////
#define __Pyx_PyNumber_InPlacePowerOf2(a, b, c) __Pyx__PyNumber_PowerOf2(a, b, c, 1)
...
...
tests/run/builtin_float.py
View file @
99b874cb
# mode: run
# tag: pure3.0
import
cython
def
empty_float
():
"""
...
...
@@ -26,3 +30,31 @@ def float_call_conjugate():
"""
x
=
float
(
1.5
).
conjugate
()
return
x
@
cython
.
test_assert_path_exists
(
"//CoerceToPyTypeNode"
,
"//CoerceToPyTypeNode//PythonCapiCallNode"
,
)
def
from_bytes
(
s
:
bytes
):
"""
>>> from_bytes(b"123")
123.0
>>> from_bytes(b"123.25")
123.25
>>> from_bytes(b"123E100")
1.23e+102
"""
return
float
(
s
)
@
cython
.
test_assert_path_exists
(
"//CoerceToPyTypeNode"
,
"//CoerceToPyTypeNode//PythonCapiCallNode"
,
)
def
from_bytes_literals
():
"""
>>> from_bytes_literals()
(123.0, 123.23, 1e+100)
"""
return
float
(
b"123"
),
float
(
b"123.23"
),
float
(
b"1e100"
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment