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
Gwenaël Samain
cython
Commits
6c3f2815
Commit
6c3f2815
authored
Sep 08, 2016
by
Robert Bradshaw
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'typeid'
parents
d84f6476
eb5fc339
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
175 additions
and
4 deletions
+175
-4
CHANGES.rst
CHANGES.rst
+2
-0
Cython/Compiler/CythonScope.py
Cython/Compiler/CythonScope.py
+3
-1
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+73
-1
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/ParseTreeTransforms.py
+1
-0
Cython/Includes/libcpp/typeindex.pxd
Cython/Includes/libcpp/typeindex.pxd
+15
-0
Cython/Includes/libcpp/typeinfo.pxd
Cython/Includes/libcpp/typeinfo.pxd
+10
-0
Cython/Parser/Grammar
Cython/Parser/Grammar
+1
-0
Cython/Utility/CppSupport.cpp
Cython/Utility/CppSupport.cpp
+2
-0
Cython/Utility/ModuleSetupCode.c
Cython/Utility/ModuleSetupCode.c
+3
-0
docs/src/userguide/wrapping_CPlusPlus.rst
docs/src/userguide/wrapping_CPlusPlus.rst
+23
-0
tests/run/cpp_operators.pyx
tests/run/cpp_operators.pyx
+41
-2
tests/run/cpp_operators_helper.h
tests/run/cpp_operators_helper.h
+1
-0
No files found.
CHANGES.rst
View file @
6c3f2815
...
@@ -42,6 +42,8 @@ Features added
...
@@ -42,6 +42,8 @@ Features added
* Some integer operations on Python long objects are faster in Python 2.7.
* Some integer operations on Python long objects are faster in Python 2.7.
* Support for the C++ ``typeid`` operator.
Bugs fixed
Bugs fixed
----------
----------
...
...
Cython/Compiler/CythonScope.py
View file @
6c3f2815
...
@@ -67,7 +67,9 @@ class CythonScope(ModuleScope):
...
@@ -67,7 +67,9 @@ class CythonScope(ModuleScope):
name_path
=
qname
.
split
(
u'.'
)
name_path
=
qname
.
split
(
u'.'
)
scope
=
self
scope
=
self
while
len
(
name_path
)
>
1
:
while
len
(
name_path
)
>
1
:
scope
=
scope
.
lookup_here
(
name_path
[
0
]).
as_module
scope
=
scope
.
lookup_here
(
name_path
[
0
])
if
scope
:
scope
=
scope
.
as_module
del
name_path
[
0
]
del
name_path
[
0
]
if
scope
is
None
:
if
scope
is
None
:
return
None
return
None
...
...
Cython/Compiler/ExprNodes.py
View file @
6c3f2815
...
@@ -6241,6 +6241,7 @@ class AttributeNode(ExprNode):
...
@@ -6241,6 +6241,7 @@ class AttributeNode(ExprNode):
needs_none_check
=
True
needs_none_check
=
True
is_memslice_transpose
=
False
is_memslice_transpose
=
False
is_special_lookup
=
False
is_special_lookup
=
False
is_py_attr
=
0
def
as_cython_attribute
(
self
):
def
as_cython_attribute
(
self
):
if
(
isinstance
(
self
.
obj
,
NameNode
)
and
if
(
isinstance
(
self
.
obj
,
NameNode
)
and
...
@@ -6670,7 +6671,7 @@ class AttributeNode(ExprNode):
...
@@ -6670,7 +6671,7 @@ class AttributeNode(ExprNode):
else
:
else
:
# result_code contains what is needed, but we may need to insert
# result_code contains what is needed, but we may need to insert
# a check and raise an exception
# a check and raise an exception
if
self
.
obj
.
type
.
is_extension_type
:
if
self
.
obj
.
type
and
self
.
obj
.
type
.
is_extension_type
:
pass
pass
elif
self
.
entry
and
self
.
entry
.
is_cmethod
:
elif
self
.
entry
and
self
.
entry
.
is_cmethod
:
# C method implemented as function call with utility code
# C method implemented as function call with utility code
...
@@ -10213,6 +10214,8 @@ class SizeofTypeNode(SizeofNode):
...
@@ -10213,6 +10214,8 @@ class SizeofTypeNode(SizeofNode):
def
check_type
(
self
):
def
check_type
(
self
):
arg_type
=
self
.
arg_type
arg_type
=
self
.
arg_type
if
not
arg_type
:
return
if
arg_type
.
is_pyobject
and
not
arg_type
.
is_extension_type
:
if
arg_type
.
is_pyobject
and
not
arg_type
.
is_extension_type
:
error
(
self
.
pos
,
"Cannot take sizeof Python object"
)
error
(
self
.
pos
,
"Cannot take sizeof Python object"
)
elif
arg_type
.
is_void
:
elif
arg_type
.
is_void
:
...
@@ -10257,6 +10260,75 @@ class SizeofVarNode(SizeofNode):
...
@@ -10257,6 +10260,75 @@ class SizeofVarNode(SizeofNode):
def
generate_result_code
(
self
,
code
):
def
generate_result_code
(
self
,
code
):
pass
pass
class
TypeidNode
(
ExprNode
):
# C++ typeid operator applied to a type or variable
#
# operand ExprNode
# arg_type ExprNode
# is_variable boolean
type
=
PyrexTypes
.
error_type
subexprs
=
[
'operand'
]
arg_type
=
None
is_variable
=
None
is_temp
=
1
def
get_type_info_type
(
self
,
env
):
env_module
=
env
while
not
env_module
.
is_module_scope
:
env_module
=
env_module
.
outer_scope
typeinfo_module
=
env_module
.
find_module
(
'libcpp.typeinfo'
,
self
.
pos
)
typeinfo_entry
=
typeinfo_module
.
lookup
(
'type_info'
)
return
PyrexTypes
.
CFakeReferenceType
(
PyrexTypes
.
c_const_type
(
typeinfo_entry
.
type
))
def
analyse_types
(
self
,
env
):
type_info
=
self
.
get_type_info_type
(
env
)
if
not
type_info
:
self
.
error
(
"The 'libcpp.typeinfo' module must be cimported to use the typeid() operator"
)
return
self
self
.
type
=
type_info
as_type
=
self
.
operand
.
analyse_as_type
(
env
)
if
as_type
:
self
.
arg_type
=
as_type
self
.
is_type
=
True
else
:
self
.
arg_type
=
self
.
operand
.
analyse_types
(
env
)
self
.
is_type
=
False
if
self
.
arg_type
.
type
.
is_pyobject
:
self
.
error
(
"Cannot use typeid on a Python object"
)
return
self
elif
self
.
arg_type
.
type
.
is_void
:
self
.
error
(
"Cannot use typeid on void"
)
return
self
elif
not
self
.
arg_type
.
type
.
is_complete
():
self
.
error
(
"Cannot use typeid on incomplete type '%s'"
%
self
.
arg_type
.
type
)
return
self
env
.
use_utility_code
(
UtilityCode
.
load_cached
(
"CppExceptionConversion"
,
"CppSupport.cpp"
))
return
self
def
error
(
self
,
mess
):
error
(
self
.
pos
,
mess
)
self
.
type
=
PyrexTypes
.
error_type
self
.
result_code
=
"<error>"
def
check_const
(
self
):
return
True
def
calculate_result_code
(
self
):
return
self
.
temp_code
def
generate_result_code
(
self
,
code
):
if
self
.
is_type
:
arg_code
=
self
.
arg_type
.
empty_declaration_code
()
else
:
arg_code
=
self
.
arg_type
.
result
()
translate_cpp_exception
(
code
,
self
.
pos
,
"%s = typeid(%s);"
%
(
self
.
temp_code
,
arg_code
),
None
,
self
.
in_nogil_context
)
class
TypeofNode
(
ExprNode
):
class
TypeofNode
(
ExprNode
):
# Compile-time type of an expression, as a string.
# Compile-time type of an expression, as a string.
#
#
...
...
Cython/Compiler/ParseTreeTransforms.py
View file @
6c3f2815
...
@@ -635,6 +635,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
...
@@ -635,6 +635,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
'operator.predecrement'
:
ExprNodes
.
inc_dec_constructor
(
True
,
'--'
),
'operator.predecrement'
:
ExprNodes
.
inc_dec_constructor
(
True
,
'--'
),
'operator.postincrement'
:
ExprNodes
.
inc_dec_constructor
(
False
,
'++'
),
'operator.postincrement'
:
ExprNodes
.
inc_dec_constructor
(
False
,
'++'
),
'operator.postdecrement'
:
ExprNodes
.
inc_dec_constructor
(
False
,
'--'
),
'operator.postdecrement'
:
ExprNodes
.
inc_dec_constructor
(
False
,
'--'
),
'operator.typeid'
:
ExprNodes
.
TypeidNode
,
# For backwards compatibility.
# For backwards compatibility.
'address'
:
ExprNodes
.
AmpersandNode
,
'address'
:
ExprNodes
.
AmpersandNode
,
...
...
Cython/Includes/libcpp/typeindex.pxd
0 → 100644
View file @
6c3f2815
from
libcpp
cimport
bool
from
.typeinfo
cimport
type_info
# This class is C++11-only
cdef
extern
from
"<typeindex>"
namespace
"std"
nogil
:
cdef
cppclass
type_index
:
type_index
(
const
type_info
&
)
const
char
*
name
()
size_t
hash_code
()
bool
operator
==
(
const
type_index
&
)
bool
operator
!=
(
const
type_index
&
)
bool
operator
<
(
const
type_index
&
)
bool
operator
<=
(
const
type_index
&
)
bool
operator
>
(
const
type_index
&
)
bool
operator
>=
(
const
type_index
&
)
Cython/Includes/libcpp/typeinfo.pxd
0 → 100644
View file @
6c3f2815
from
libcpp
cimport
bool
cdef
extern
from
"<typeinfo>"
namespace
"std"
nogil
:
cdef
cppclass
type_info
:
const
char
*
name
()
int
before
(
const
type_info
&
)
bool
operator
==
(
const
type_info
&
)
bool
operator
!=
(
const
type_info
&
)
# C++11-only
size_t
hash_code
()
Cython/Parser/Grammar
View file @
6c3f2815
...
@@ -167,6 +167,7 @@ memory_view_index: ':' [':'] [NUMBER]
...
@@ -167,6 +167,7 @@ memory_view_index: ':' [':'] [NUMBER]
address: '&' factor
address: '&' factor
cast: '<' type ['?'] '>' factor
cast: '<' type ['?'] '>' factor
size_of: 'sizeof' '(' (type) ')'
size_of: 'sizeof' '(' (type) ')'
type_id: 'typeid' '(' (type) ')'
new_expr: 'new' type '(' [arglist] ')'
new_expr: 'new' type '(' [arglist] ')'
# TODO: Restrict cdef_stmt to "top-level" statements.
# TODO: Restrict cdef_stmt to "top-level" statements.
...
...
Cython/Utility/CppSupport.cpp
View file @
6c3f2815
...
@@ -18,6 +18,8 @@ static void __Pyx_CppExn2PyErr() {
...
@@ -18,6 +18,8 @@ static void __Pyx_CppExn2PyErr() {
PyErr_SetString
(
PyExc_MemoryError
,
exn
.
what
());
PyErr_SetString
(
PyExc_MemoryError
,
exn
.
what
());
}
catch
(
const
std
::
bad_cast
&
exn
)
{
}
catch
(
const
std
::
bad_cast
&
exn
)
{
PyErr_SetString
(
PyExc_TypeError
,
exn
.
what
());
PyErr_SetString
(
PyExc_TypeError
,
exn
.
what
());
}
catch
(
const
std
::
bad_typeid
&
exn
)
{
PyErr_SetString
(
PyExc_TypeError
,
exn
.
what
());
}
catch
(
const
std
::
domain_error
&
exn
)
{
}
catch
(
const
std
::
domain_error
&
exn
)
{
PyErr_SetString
(
PyExc_ValueError
,
exn
.
what
());
PyErr_SetString
(
PyExc_ValueError
,
exn
.
what
());
}
catch
(
const
std
::
invalid_argument
&
exn
)
{
}
catch
(
const
std
::
invalid_argument
&
exn
)
{
...
...
Cython/Utility/ModuleSetupCode.c
View file @
6c3f2815
...
@@ -403,6 +403,9 @@ class __Pyx_FakeReference {
...
@@ -403,6 +403,9 @@ class __Pyx_FakeReference {
__Pyx_FakeReference
(
const
T
&
ref
)
:
ptr
(
const_cast
<
T
*>
(
&
ref
))
{
}
__Pyx_FakeReference
(
const
T
&
ref
)
:
ptr
(
const_cast
<
T
*>
(
&
ref
))
{
}
T
*
operator
->
()
{
return
ptr
;
}
T
*
operator
->
()
{
return
ptr
;
}
operator
T
&
()
{
return
*
ptr
;
}
operator
T
&
()
{
return
*
ptr
;
}
// TODO(robertwb): Delegate all operators (or auto-generate unwrapping code where needed).
template
<
typename
U
>
bool
operator
==
(
U
other
)
{
return
*
ptr
==
other
;
};
template
<
typename
U
>
bool
operator
!=
(
U
other
)
{
return
*
ptr
!=
other
;
};
private:
private:
T
*
ptr
;
T
*
ptr
;
};
};
...
...
docs/src/userguide/wrapping_CPlusPlus.rst
View file @
6c3f2815
...
@@ -562,6 +562,8 @@ The translation is performed according to the following table
...
@@ -562,6 +562,8 @@ The translation is performed according to the following table
+-----------------------+---------------------+
+-----------------------+---------------------+
| ``bad_cast`` | ``TypeError`` |
| ``bad_cast`` | ``TypeError`` |
+-----------------------+---------------------+
+-----------------------+---------------------+
| ``bad_typeid`` | ``TypeError`` |
+-----------------------+---------------------+
| ``domain_error`` | ``ValueError`` |
| ``domain_error`` | ``ValueError`` |
+-----------------------+---------------------+
+-----------------------+---------------------+
| ``invalid_argument`` | ``ValueError`` |
| ``invalid_argument`` | ``ValueError`` |
...
@@ -646,6 +648,27 @@ e.g.::
...
@@ -646,6 +648,27 @@ e.g.::
(Though of course the ``for .. in`` syntax is prefered for objects supporting
(Though of course the ``for .. in`` syntax is prefered for objects supporting
the iteration protocol.)
the iteration protocol.)
RTTI and typeid()
=================
Cython has support for the ``typeid(...)`` operator.
from cython.operator cimport typeid
The ``typeid(...)`` operator returns an object of the type ``const type_info &``.
If you want to store a type_info value in a C variable, you will need to store it
as a pointer rather than a reference:
from libcpp.typeinfo cimport type_info
cdef const type_info* info = &typeid(MyClass)
If an invalid type is passed to ``typeid``, it will throw an ``std::bad_typeid``
exception which is converted into a ``TypeError`` exception in Python.
An additional C++11-only RTTI-related class, ``std::type_index``, is available
in ``libcpp.typeindex``.
Caveats and Limitations
Caveats and Limitations
========================
========================
...
...
tests/run/cpp_operators.pyx
View file @
6c3f2815
...
@@ -4,7 +4,7 @@
...
@@ -4,7 +4,7 @@
from
cython
cimport
typeof
from
cython
cimport
typeof
cimport
cython.operator
cimport
cython.operator
from
cython.operator
cimport
dereference
as
deref
from
cython.operator
cimport
typeid
,
dereference
as
deref
from
libc.string
cimport
const_char
from
libc.string
cimport
const_char
from
libcpp
cimport
bool
from
libcpp
cimport
bool
...
@@ -50,12 +50,15 @@ cdef extern from "cpp_operators_helper.h":
...
@@ -50,12 +50,15 @@ cdef extern from "cpp_operators_helper.h":
const_char
*
operator
[](
int
)
const_char
*
operator
[](
int
)
const_char
*
operator
()(
int
)
const_char
*
operator
()(
int
)
cppclass
TruthClass
:
c
def
c
ppclass
TruthClass
:
TruthClass
()
TruthClass
()
TruthClass
(
bool
)
TruthClass
(
bool
)
bool
operator
bool
()
bool
operator
bool
()
bool
value
bool
value
cdef
cppclass
TruthSubClass
(
TruthClass
):
pass
def
test_unops
():
def
test_unops
():
"""
"""
>>> test_unops()
>>> test_unops()
...
@@ -182,3 +185,39 @@ def test_bool_cond():
...
@@ -182,3 +185,39 @@ def test_bool_cond():
assert
(
TruthClass
(
False
)
and
TruthClass
(
True
)).
value
==
False
assert
(
TruthClass
(
False
)
and
TruthClass
(
True
)).
value
==
False
assert
(
TruthClass
(
True
)
and
TruthClass
(
False
)).
value
==
False
assert
(
TruthClass
(
True
)
and
TruthClass
(
False
)).
value
==
False
assert
(
TruthClass
(
True
)
and
TruthClass
(
True
)).
value
==
True
assert
(
TruthClass
(
True
)
and
TruthClass
(
True
)).
value
==
True
ctypedef
int
*
int_ptr
def
test_typeid_op
():
"""
>>> test_typeid_op()
"""
cdef
TruthClass
*
test_1
=
new
TruthClass
()
cdef
TruthSubClass
*
test_2
=
new
TruthSubClass
()
cdef
TruthClass
*
test_3
=
<
TruthClass
*>
test_2
cdef
TruthClass
*
test_4
=
<
TruthClass
*>
0
assert
typeid
(
TruthClass
).
name
()
assert
typeid
(
test_1
).
name
()
assert
typeid
(
TruthClass
)
==
typeid
(
deref
(
test_1
))
assert
typeid
(
TruthSubClass
).
name
()
assert
typeid
(
test_2
).
name
()
assert
typeid
(
TruthSubClass
)
==
typeid
(
deref
(
test_2
))
assert
typeid
(
TruthSubClass
)
==
typeid
(
deref
(
test_3
))
assert
typeid
(
TruthClass
)
!=
typeid
(
deref
(
test_3
))
assert
typeid
(
TruthClass
).
name
()
assert
typeid
(
test_3
).
name
()
assert
typeid
(
TruthSubClass
).
name
()
assert
typeid
(
deref
(
test_2
)).
name
()
assert
typeid
(
int_ptr
).
name
()
try
:
typeid
(
deref
(
test_4
))
assert
False
except
TypeError
:
assert
True
del
test_1
,
test_2
tests/run/cpp_operators_helper.h
View file @
6c3f2815
...
@@ -50,6 +50,7 @@ class TruthClass {
...
@@ -50,6 +50,7 @@ class TruthClass {
public:
public:
TruthClass
()
:
value
(
false
)
{}
TruthClass
()
:
value
(
false
)
{}
TruthClass
(
bool
value
)
:
value
(
value
)
{}
TruthClass
(
bool
value
)
:
value
(
value
)
{}
virtual
~
TruthClass
()
{};
operator
bool
()
{
return
value
;
}
operator
bool
()
{
return
value
;
}
bool
value
;
bool
value
;
};
};
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