Commit 152fa006 authored by scoder's avatar scoder

Merge pull request #114 from scoder/_charptr_cleanup

Cleanup of charptr handling to improve typedef support
parents 8ded353d e3838e42
......@@ -333,6 +333,12 @@ class CTypedefType(BaseType):
def __repr__(self):
return "<CTypedefType %s>" % self.typedef_cname
def __hash__(self):
return hash(self.typedef_base_type)
def __eq__(self, other):
return other == self.typedef_base_type
def __str__(self):
return self.typedef_name
......@@ -2130,19 +2136,61 @@ impl="""
#endif
""")
class CArrayType(CType):
class CPointerBaseType(CType):
# common base type for pointer/array types
#
# base_type CType Reference type
subtypes = ['base_type']
def __init__(self, base_type):
self.base_type = base_type
for char_type in (c_char_type, c_uchar_type, c_schar_type):
if base_type.same_as(char_type):
self.is_string = 1
break
if self.is_string and not base_type.is_error:
if base_type.signed:
self.to_py_function = "PyBytes_FromString"
if self.is_ptr:
self.from_py_function = "PyBytes_AsString"
else:
self.to_py_function = "__Pyx_PyBytes_FromUString"
if self.is_ptr:
self.from_py_function = "__Pyx_PyBytes_AsUString"
self.exception_value = "NULL"
def __hash__(self):
return hash(self.base_type) + self.is_ptr + 27 # arbitrarily chosen offset
def py_type_name(self):
if self.is_string:
return "bytes"
else:
return super(CPointerBaseType, self).py_type_name()
def literal_code(self, value):
if self.is_string:
assert isinstance(value, str)
return '"%s"' % StringEncoding.escape_byte_string(value)
class CArrayType(CPointerBaseType):
# base_type CType Element type
# size integer or None Number of elements
is_array = 1
subtypes = ['base_type']
def __init__(self, base_type, size):
self.base_type = base_type
super(CArrayType, self).__init__(base_type)
self.size = size
if base_type in (c_char_type, c_uchar_type, c_schar_type):
self.is_string = 1
def __eq__(self, other):
if isinstance(other, CType):
if self.is_array and other.is_array and self.size == other.size:
return self.base_type.same_as(other.base_type)
return False
def __repr__(self):
return "<CArrayType %s %s>" % (self.size, repr(self.base_type))
......@@ -2178,16 +2226,16 @@ class CArrayType(CType):
return self.size is not None
class CPtrType(CType):
# base_type CType Referenced type
class CPtrType(CPointerBaseType):
# base_type CType Reference type
is_ptr = 1
default_value = "0"
subtypes = ['base_type']
def __init__(self, base_type):
self.base_type = base_type
def __eq__(self, other):
if isinstance(other, CType) and other.is_ptr:
return self.base_type.same_as(other.base_type)
return False
def __repr__(self):
return "<CPtrType %s>" % repr(self.base_type)
......@@ -3104,63 +3152,6 @@ class CEnumType(CType):
base_code = public_decl(base_code, dll_linkage)
return self.base_declaration_code(base_code, entity_code)
class CStringType(object):
# Mixin class for C string types.
is_string = 1
is_unicode = 0
to_py_function = "PyBytes_FromString"
from_py_function = "PyBytes_AsString"
exception_value = "NULL"
def literal_code(self, value):
assert isinstance(value, str)
return '"%s"' % StringEncoding.escape_byte_string(value)
def py_type_name(self):
if self.is_unicode:
return "unicode"
return "bytes"
class CUTF8CharArrayType(CStringType, CArrayType):
# C 'char []' type.
is_unicode = 1
to_py_function = "PyUnicode_DecodeUTF8"
exception_value = "NULL"
def __init__(self, size):
CArrayType.__init__(self, c_char_type, size)
class CCharArrayType(CStringType, CArrayType):
# C 'char []' type.
from_py_function = None
def __init__(self, size):
CArrayType.__init__(self, c_char_type, size)
class CCharPtrType(CStringType, CPtrType):
# C 'char *' type.
def __init__(self):
CPtrType.__init__(self, c_char_type)
class CUCharPtrType(CStringType, CPtrType):
# C 'unsigned char *' type.
to_py_function = "__Pyx_PyBytes_FromUString"
from_py_function = "__Pyx_PyBytes_AsUString"
def __init__(self):
CPtrType.__init__(self, c_uchar_type)
class UnspecifiedType(PyrexType):
# Used as a placeholder until the type can be determined.
......@@ -3218,6 +3209,8 @@ RANK_FLOAT = _rank_to_type_name.index('float')
UNSIGNED = 0
SIGNED = 2
error_type = ErrorType()
unspecified_type = UnspecifiedType()
py_object_type = PyObjectType()
......@@ -3262,10 +3255,8 @@ c_size_t_type = CSizeTType(RANK_LONG+0.5, UNSIGNED)
c_null_ptr_type = CNullPtrType(c_void_type)
c_void_ptr_type = CPtrType(c_void_type)
c_void_ptr_ptr_type = CPtrType(c_void_ptr_type)
c_char_array_type = CCharArrayType(None)
c_char_ptr_type = CCharPtrType()
c_uchar_ptr_type = CUCharPtrType()
c_utf8_char_array_type = CUTF8CharArrayType(None)
c_char_ptr_type = CPtrType(c_char_type)
c_uchar_ptr_type = CPtrType(c_uchar_type)
c_char_ptr_ptr_type = CPtrType(c_char_ptr_type)
c_int_ptr_type = CPtrType(c_int_type)
c_py_unicode_ptr_type = CPtrType(c_py_unicode_type)
......@@ -3309,9 +3300,6 @@ cython_memoryview_ptr_type = CPtrType(cython_memoryview_type)
memoryviewslice_type = CStructOrUnionType("memoryviewslice", "struct",
None, 1, "__Pyx_memviewslice")
error_type = ErrorType()
unspecified_type = UnspecifiedType()
modifiers_and_name_to_type = {
#(signed, longness, name) : type
(0, 0, "char"): c_uchar_type,
......@@ -3668,20 +3656,14 @@ def parse_basic_type(name):
def c_array_type(base_type, size):
# Construct a C array type.
if base_type is c_char_type:
return CCharArrayType(size)
elif base_type is error_type:
if base_type is error_type:
return error_type
else:
return CArrayType(base_type, size)
def c_ptr_type(base_type):
# Construct a C pointer type.
if base_type is c_char_type:
return c_char_ptr_type
elif base_type is c_uchar_type:
return c_uchar_ptr_type
elif base_type is error_type:
if base_type is error_type:
return error_type
else:
return CPtrType(base_type)
......
......@@ -2,6 +2,8 @@
cdef extern from *:
ctypedef char const_char "const char"
ctypedef signed char const_schar "const signed char"
ctypedef unsigned char const_uchar "const unsigned char"
ctypedef void const_void "const void"
cdef extern from "string.h" nogil:
......
cimport cython
from cython cimport typeof
from libc.string cimport const_char, const_uchar
@cython.test_assert_path_exists(
"//NameNode[@name = 'st' and @type.is_string = True]",
"//NameNode[@name = 'ust' and @type.is_string = True]",
"//NameNode[@name = 'my_st' and @type.is_string = True]",
"//NameNode[@name = 'my_ust' and @type.is_string = True]",
)
def const_charptrs():
"""
>>> const_charptrs()
"""
cdef object obj
cdef const_char* st = b'XYZ'
cdef const_uchar* ust = <unsigned char*>b'XYZ' # needs cast to unsigned
assert typeof(st) == "const_char *", typeof(st)
my_st = st
assert typeof(my_st) == "const_char *", typeof(my_st)
obj = my_st
assert obj == b'XYZ'
assert typeof(ust) == "const_uchar *", typeof(ust)
my_ust = ust
assert typeof(my_ust) == "const_uchar *", typeof(my_ust)
obj = my_ust
assert obj == b'XYZ'
ctypedef char mychar
ctypedef unsigned char myuchar
def const_char_arrays():
"""
>>> const_char_arrays()
"""
cdef int i
cdef object obj
cdef mychar[4] st
cdef myuchar[4] ust
i = 0
for ch in <char*>b'XYZ\0':
st[i] = ch
ust[i] = ch
i += 1
assert typeof(st) == "mychar [4]", typeof(st)
obj = st
assert obj == b'XYZ'
assert typeof(ust) == "myuchar [4]", typeof(ust)
obj = ust
assert obj == b'XYZ'
......@@ -47,9 +47,9 @@ def test_cdef_func_with_fused_args():
4.2 8.6 bunny
12.8
"""
print cdef_func_with_fused_args('spam', 'ham', 'eggs').decode('ascii')
print cdef_func_with_fused_args(10, 20, 'butter')
print cdef_func_with_fused_args(4.2, 8.6, 'bunny')
print cdef_func_with_fused_args(b'spam', b'ham', b'eggs').decode('ascii')
print cdef_func_with_fused_args(10, 20, b'butter')
print cdef_func_with_fused_args(4.2, 8.6, b'bunny')
cdef fused_type1 fused_with_pointer(fused_type1 *array):
for i in range(5):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment