Index: third_party/cython/src/Cython/Compiler/PyrexTypes.py |
diff --git a/third_party/cython/src/Cython/Compiler/PyrexTypes.py b/third_party/cython/src/Cython/Compiler/PyrexTypes.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..7ee2a98de97f982052c9b97f463582b9b532b064 |
--- /dev/null |
+++ b/third_party/cython/src/Cython/Compiler/PyrexTypes.py |
@@ -0,0 +1,3875 @@ |
+# |
+# Cython/Python language types |
+# |
+ |
+from Code import UtilityCode, LazyUtilityCode, TempitaUtilityCode |
+import StringEncoding |
+import Naming |
+import copy |
+from Errors import error |
+ |
+class BaseType(object): |
+ # |
+ # Base class for all Cython types including pseudo-types. |
+ |
+ # List of attribute names of any subtypes |
+ subtypes = [] |
+ |
+ def can_coerce_to_pyobject(self, env): |
+ return False |
+ |
+ def cast_code(self, expr_code): |
+ return "((%s)%s)" % (self.declaration_code(""), expr_code) |
+ |
+ def specialization_name(self): |
+ # This is not entirely robust. |
+ safe = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_0123456789' |
+ all = [] |
+ for c in self.declaration_code("").replace("unsigned ", "unsigned_").replace("long long", "long_long").replace(" ", "__"): |
+ if c in safe: |
+ all.append(c) |
+ else: |
+ all.append('_%x_' % ord(c)) |
+ return ''.join(all) |
+ |
+ def base_declaration_code(self, base_code, entity_code): |
+ if entity_code: |
+ return "%s %s" % (base_code, entity_code) |
+ else: |
+ return base_code |
+ |
+ def __deepcopy__(self, memo): |
+ """ |
+ Types never need to be copied, if we do copy, Unfortunate Things |
+ Will Happen! |
+ """ |
+ return self |
+ |
+ def get_fused_types(self, result=None, seen=None, subtypes=None): |
+ subtypes = subtypes or self.subtypes |
+ if subtypes: |
+ if result is None: |
+ result = [] |
+ seen = set() |
+ |
+ for attr in subtypes: |
+ list_or_subtype = getattr(self, attr) |
+ if list_or_subtype: |
+ if isinstance(list_or_subtype, BaseType): |
+ list_or_subtype.get_fused_types(result, seen) |
+ else: |
+ for subtype in list_or_subtype: |
+ subtype.get_fused_types(result, seen) |
+ |
+ return result |
+ |
+ return None |
+ |
+ def specialize_fused(self, env): |
+ if env.fused_to_specific: |
+ return self.specialize(env.fused_to_specific) |
+ |
+ return self |
+ |
+ def _get_fused_types(self): |
+ """ |
+ Add this indirection for the is_fused property to allow overriding |
+ get_fused_types in subclasses. |
+ """ |
+ return self.get_fused_types() |
+ |
+ is_fused = property(_get_fused_types, doc="Whether this type or any of its " |
+ "subtypes is a fused type") |
+ |
+ def deduce_template_params(self, actual): |
+ """ |
+ Deduce any template params in this (argument) type given the actual |
+ argument type. |
+ |
+ http://en.cppreference.com/w/cpp/language/function_template#Template_argument_deduction |
+ """ |
+ if self == actual: |
+ return {} |
+ else: |
+ return None |
+ |
+ def __lt__(self, other): |
+ """ |
+ For sorting. The sorting order should correspond to the preference of |
+ conversion from Python types. |
+ |
+ Override to provide something sensible. This is only implemented so that |
+ python 3 doesn't trip |
+ """ |
+ return id(type(self)) < id(type(other)) |
+ |
+ def py_type_name(self): |
+ """ |
+ Return the name of the Python type that can coerce to this type. |
+ """ |
+ |
+ def typeof_name(self): |
+ """ |
+ Return the string with which fused python functions can be indexed. |
+ """ |
+ if self.is_builtin_type or self.py_type_name() == 'object': |
+ index_name = self.py_type_name() |
+ else: |
+ index_name = str(self) |
+ |
+ return index_name |
+ |
+ def check_for_null_code(self, cname): |
+ """ |
+ Return the code for a NULL-check in case an UnboundLocalError should |
+ be raised if an entry of this type is referenced before assignment. |
+ Returns None if no check should be performed. |
+ """ |
+ return None |
+ |
+ def invalid_value(self): |
+ """ |
+ Returns the most invalid value an object of this type can assume as a |
+ C expression string. Returns None if no such value exists. |
+ """ |
+ |
+ |
+class PyrexType(BaseType): |
+ # |
+ # Base class for all Cython types |
+ # |
+ # is_pyobject boolean Is a Python object type |
+ # is_extension_type boolean Is a Python extension type |
+ # is_final_type boolean Is a final extension type |
+ # is_numeric boolean Is a C numeric type |
+ # is_int boolean Is a C integer type |
+ # is_float boolean Is a C floating point type |
+ # is_complex boolean Is a C complex type |
+ # is_void boolean Is the C void type |
+ # is_array boolean Is a C array type |
+ # is_ptr boolean Is a C pointer type |
+ # is_null_ptr boolean Is the type of NULL |
+ # is_reference boolean Is a C reference type |
+ # is_const boolean Is a C const type. |
+ # is_cfunction boolean Is a C function type |
+ # is_struct_or_union boolean Is a C struct or union type |
+ # is_struct boolean Is a C struct type |
+ # is_enum boolean Is a C enum type |
+ # is_typedef boolean Is a typedef type |
+ # is_string boolean Is a C char * type |
+ # is_pyunicode_ptr boolean Is a C PyUNICODE * type |
+ # is_cpp_string boolean Is a C++ std::string type |
+ # is_unicode_char boolean Is either Py_UCS4 or Py_UNICODE |
+ # is_returncode boolean Is used only to signal exceptions |
+ # is_error boolean Is the dummy error type |
+ # is_buffer boolean Is buffer access type |
+ # has_attributes boolean Has C dot-selectable attributes |
+ # default_value string Initial value |
+ # entry Entry The Entry for this type |
+ # |
+ # declaration_code(entity_code, |
+ # for_display = 0, dll_linkage = None, pyrex = 0) |
+ # Returns a code fragment for the declaration of an entity |
+ # of this type, given a code fragment for the entity. |
+ # * If for_display, this is for reading by a human in an error |
+ # message; otherwise it must be valid C code. |
+ # * If dll_linkage is not None, it must be 'DL_EXPORT' or |
+ # 'DL_IMPORT', and will be added to the base type part of |
+ # the declaration. |
+ # * If pyrex = 1, this is for use in a 'cdef extern' |
+ # statement of a Cython include file. |
+ # |
+ # assignable_from(src_type) |
+ # Tests whether a variable of this type can be |
+ # assigned a value of type src_type. |
+ # |
+ # same_as(other_type) |
+ # Tests whether this type represents the same type |
+ # as other_type. |
+ # |
+ # as_argument_type(): |
+ # Coerces array and C function types into pointer type for use as |
+ # a formal argument type. |
+ # |
+ |
+ is_pyobject = 0 |
+ is_unspecified = 0 |
+ is_extension_type = 0 |
+ is_final_type = 0 |
+ is_builtin_type = 0 |
+ is_numeric = 0 |
+ is_int = 0 |
+ is_float = 0 |
+ is_complex = 0 |
+ is_void = 0 |
+ is_array = 0 |
+ is_ptr = 0 |
+ is_null_ptr = 0 |
+ is_reference = 0 |
+ is_const = 0 |
+ is_cfunction = 0 |
+ is_struct_or_union = 0 |
+ is_cpp_class = 0 |
+ is_cpp_string = 0 |
+ is_struct = 0 |
+ is_enum = 0 |
+ is_typedef = 0 |
+ is_string = 0 |
+ is_pyunicode_ptr = 0 |
+ is_unicode_char = 0 |
+ is_returncode = 0 |
+ is_error = 0 |
+ is_buffer = 0 |
+ is_memoryviewslice = 0 |
+ has_attributes = 0 |
+ default_value = "" |
+ |
+ def resolve(self): |
+ # If a typedef, returns the base type. |
+ return self |
+ |
+ def specialize(self, values): |
+ # TODO(danilo): Override wherever it makes sense. |
+ return self |
+ |
+ def literal_code(self, value): |
+ # Returns a C code fragment representing a literal |
+ # value of this type. |
+ return str(value) |
+ |
+ def __str__(self): |
+ return self.declaration_code("", for_display = 1).strip() |
+ |
+ def same_as(self, other_type, **kwds): |
+ return self.same_as_resolved_type(other_type.resolve(), **kwds) |
+ |
+ def same_as_resolved_type(self, other_type): |
+ return self == other_type or other_type is error_type |
+ |
+ def subtype_of(self, other_type): |
+ return self.subtype_of_resolved_type(other_type.resolve()) |
+ |
+ def subtype_of_resolved_type(self, other_type): |
+ return self.same_as(other_type) |
+ |
+ def assignable_from(self, src_type): |
+ return self.assignable_from_resolved_type(src_type.resolve()) |
+ |
+ def assignable_from_resolved_type(self, src_type): |
+ return self.same_as(src_type) |
+ |
+ def as_argument_type(self): |
+ return self |
+ |
+ def is_complete(self): |
+ # A type is incomplete if it is an unsized array, |
+ # a struct whose attributes are not defined, etc. |
+ return 1 |
+ |
+ def is_simple_buffer_dtype(self): |
+ return (self.is_int or self.is_float or self.is_complex or self.is_pyobject or |
+ self.is_extension_type or self.is_ptr) |
+ |
+ def struct_nesting_depth(self): |
+ # Returns the number levels of nested structs. This is |
+ # used for constructing a stack for walking the run-time |
+ # type information of the struct. |
+ return 1 |
+ |
+ def global_init_code(self, entry, code): |
+ # abstract |
+ pass |
+ |
+ def needs_nonecheck(self): |
+ return 0 |
+ |
+ |
+def public_decl(base_code, dll_linkage): |
+ if dll_linkage: |
+ return "%s(%s)" % (dll_linkage, base_code) |
+ else: |
+ return base_code |
+ |
+def create_typedef_type(name, base_type, cname, is_external=0): |
+ is_fused = base_type.is_fused |
+ if base_type.is_complex or is_fused: |
+ if is_external: |
+ if is_fused: |
+ msg = "Fused" |
+ else: |
+ msg = "Complex" |
+ |
+ raise ValueError("%s external typedefs not supported" % msg) |
+ |
+ return base_type |
+ else: |
+ return CTypedefType(name, base_type, cname, is_external) |
+ |
+ |
+class CTypedefType(BaseType): |
+ # |
+ # Pseudo-type defined with a ctypedef statement in a |
+ # 'cdef extern from' block. |
+ # Delegates most attribute lookups to the base type. |
+ # (Anything not defined here or in the BaseType is delegated.) |
+ # |
+ # qualified_name string |
+ # typedef_name string |
+ # typedef_cname string |
+ # typedef_base_type PyrexType |
+ # typedef_is_external bool |
+ |
+ is_typedef = 1 |
+ typedef_is_external = 0 |
+ |
+ to_py_utility_code = None |
+ from_py_utility_code = None |
+ |
+ subtypes = ['typedef_base_type'] |
+ |
+ def __init__(self, name, base_type, cname, is_external=0): |
+ assert not base_type.is_complex |
+ self.typedef_name = name |
+ self.typedef_cname = cname |
+ self.typedef_base_type = base_type |
+ self.typedef_is_external = is_external |
+ |
+ def invalid_value(self): |
+ return self.typedef_base_type.invalid_value() |
+ |
+ def resolve(self): |
+ return self.typedef_base_type.resolve() |
+ |
+ def declaration_code(self, entity_code, |
+ for_display = 0, dll_linkage = None, pyrex = 0): |
+ if pyrex or for_display: |
+ base_code = self.typedef_name |
+ else: |
+ base_code = public_decl(self.typedef_cname, dll_linkage) |
+ return self.base_declaration_code(base_code, entity_code) |
+ |
+ def as_argument_type(self): |
+ return self |
+ |
+ def cast_code(self, expr_code): |
+ # If self is really an array (rather than pointer), we can't cast. |
+ # For example, the gmp mpz_t. |
+ if self.typedef_base_type.is_array: |
+ base_type = self.typedef_base_type.base_type |
+ return CPtrType(base_type).cast_code(expr_code) |
+ else: |
+ return BaseType.cast_code(self, expr_code) |
+ |
+ def __repr__(self): |
+ return "<CTypedefType %s>" % self.typedef_cname |
+ |
+ def __str__(self): |
+ return self.typedef_name |
+ |
+ def _create_utility_code(self, template_utility_code, |
+ template_function_name): |
+ type_name = self.typedef_cname.replace(" ","_").replace("::","__") |
+ utility_code = template_utility_code.specialize( |
+ type = self.typedef_cname, |
+ TypeName = type_name) |
+ function_name = template_function_name % type_name |
+ return utility_code, function_name |
+ |
+ def create_to_py_utility_code(self, env): |
+ if self.typedef_is_external: |
+ if not self.to_py_utility_code: |
+ base_type = self.typedef_base_type |
+ if type(base_type) is CIntType: |
+ self.to_py_function = "__Pyx_PyInt_From_" + self.specialization_name() |
+ env.use_utility_code(TempitaUtilityCode.load( |
+ "CIntToPy", "TypeConversion.c", |
+ context={"TYPE": self.declaration_code(''), |
+ "TO_PY_FUNCTION": self.to_py_function})) |
+ return True |
+ elif base_type.is_float: |
+ pass # XXX implement! |
+ elif base_type.is_complex: |
+ pass # XXX implement! |
+ pass |
+ if self.to_py_utility_code: |
+ env.use_utility_code(self.to_py_utility_code) |
+ return True |
+ # delegation |
+ return self.typedef_base_type.create_to_py_utility_code(env) |
+ |
+ def create_from_py_utility_code(self, env): |
+ if self.typedef_is_external: |
+ if not self.from_py_utility_code: |
+ base_type = self.typedef_base_type |
+ if type(base_type) is CIntType: |
+ self.from_py_function = "__Pyx_PyInt_As_" + self.specialization_name() |
+ env.use_utility_code(TempitaUtilityCode.load( |
+ "CIntFromPy", "TypeConversion.c", |
+ context={"TYPE": self.declaration_code(''), |
+ "FROM_PY_FUNCTION": self.from_py_function})) |
+ return True |
+ elif base_type.is_float: |
+ pass # XXX implement! |
+ elif base_type.is_complex: |
+ pass # XXX implement! |
+ if self.from_py_utility_code: |
+ env.use_utility_code(self.from_py_utility_code) |
+ return True |
+ # delegation |
+ return self.typedef_base_type.create_from_py_utility_code(env) |
+ |
+ def overflow_check_binop(self, binop, env, const_rhs=False): |
+ env.use_utility_code(UtilityCode.load("Common", "Overflow.c")) |
+ type = self.declaration_code("") |
+ name = self.specialization_name() |
+ if binop == "lshift": |
+ env.use_utility_code(TempitaUtilityCode.load( |
+ "LeftShift", "Overflow.c", |
+ context={'TYPE': type, 'NAME': name, 'SIGNED': self.signed})) |
+ else: |
+ if const_rhs: |
+ binop += "_const" |
+ _load_overflow_base(env) |
+ env.use_utility_code(TempitaUtilityCode.load( |
+ "SizeCheck", "Overflow.c", |
+ context={'TYPE': type, 'NAME': name})) |
+ env.use_utility_code(TempitaUtilityCode.load( |
+ "Binop", "Overflow.c", |
+ context={'TYPE': type, 'NAME': name, 'BINOP': binop})) |
+ return "__Pyx_%s_%s_checking_overflow" % (binop, name) |
+ |
+ def error_condition(self, result_code): |
+ if self.typedef_is_external: |
+ if self.exception_value: |
+ condition = "(%s == (%s)%s)" % ( |
+ result_code, self.typedef_cname, self.exception_value) |
+ if self.exception_check: |
+ condition += " && PyErr_Occurred()" |
+ return condition |
+ # delegation |
+ return self.typedef_base_type.error_condition(result_code) |
+ |
+ def __getattr__(self, name): |
+ return getattr(self.typedef_base_type, name) |
+ |
+ def py_type_name(self): |
+ return self.typedef_base_type.py_type_name() |
+ |
+ def can_coerce_to_pyobject(self, env): |
+ return self.typedef_base_type.can_coerce_to_pyobject(env) |
+ |
+ |
+class MemoryViewSliceType(PyrexType): |
+ |
+ is_memoryviewslice = 1 |
+ |
+ has_attributes = 1 |
+ scope = None |
+ |
+ # These are special cased in Defnode |
+ from_py_function = None |
+ to_py_function = None |
+ |
+ exception_value = None |
+ exception_check = True |
+ |
+ subtypes = ['dtype'] |
+ |
+ def __init__(self, base_dtype, axes): |
+ """ |
+ MemoryViewSliceType(base, axes) |
+ |
+ Base is the C base type; axes is a list of (access, packing) strings, |
+ where access is one of 'full', 'direct' or 'ptr' and packing is one of |
+ 'contig', 'strided' or 'follow'. There is one (access, packing) tuple |
+ for each dimension. |
+ |
+ the access specifiers determine whether the array data contains |
+ pointers that need to be dereferenced along that axis when |
+ retrieving/setting: |
+ |
+ 'direct' -- No pointers stored in this dimension. |
+ 'ptr' -- Pointer stored in this dimension. |
+ 'full' -- Check along this dimension, don't assume either. |
+ |
+ the packing specifiers specify how the array elements are layed-out |
+ in memory. |
+ |
+ 'contig' -- The data are contiguous in memory along this dimension. |
+ At most one dimension may be specified as 'contig'. |
+ 'strided' -- The data aren't contiguous along this dimenison. |
+ 'follow' -- Used for C/Fortran contiguous arrays, a 'follow' dimension |
+ has its stride automatically computed from extents of the other |
+ dimensions to ensure C or Fortran memory layout. |
+ |
+ C-contiguous memory has 'direct' as the access spec, 'contig' as the |
+ *last* axis' packing spec and 'follow' for all other packing specs. |
+ |
+ Fortran-contiguous memory has 'direct' as the access spec, 'contig' as |
+ the *first* axis' packing spec and 'follow' for all other packing |
+ specs. |
+ """ |
+ import MemoryView |
+ |
+ self.dtype = base_dtype |
+ self.axes = axes |
+ self.ndim = len(axes) |
+ self.flags = MemoryView.get_buf_flags(self.axes) |
+ |
+ self.is_c_contig, self.is_f_contig = MemoryView.is_cf_contig(self.axes) |
+ assert not (self.is_c_contig and self.is_f_contig) |
+ |
+ self.mode = MemoryView.get_mode(axes) |
+ self.writable_needed = False |
+ |
+ if not self.dtype.is_fused: |
+ self.dtype_name = MemoryView.mangle_dtype_name(self.dtype) |
+ |
+ def same_as_resolved_type(self, other_type): |
+ return ((other_type.is_memoryviewslice and |
+ self.dtype.same_as(other_type.dtype) and |
+ self.axes == other_type.axes) or |
+ other_type is error_type) |
+ |
+ def needs_nonecheck(self): |
+ return True |
+ |
+ def is_complete(self): |
+ # incomplete since the underlying struct doesn't have a cython.memoryview object. |
+ return 0 |
+ |
+ def declaration_code(self, entity_code, |
+ for_display = 0, dll_linkage = None, pyrex = 0): |
+ # XXX: we put these guards in for now... |
+ assert not pyrex |
+ assert not dll_linkage |
+ import MemoryView |
+ return self.base_declaration_code( |
+ MemoryView.memviewslice_cname, |
+ entity_code) |
+ |
+ def attributes_known(self): |
+ if self.scope is None: |
+ import Symtab |
+ |
+ self.scope = scope = Symtab.CClassScope( |
+ 'mvs_class_'+self.specialization_suffix(), |
+ None, |
+ visibility='extern') |
+ |
+ scope.parent_type = self |
+ scope.directives = {} |
+ |
+ scope.declare_var('_data', c_char_ptr_type, None, |
+ cname='data', is_cdef=1) |
+ |
+ return True |
+ |
+ def declare_attribute(self, attribute, env, pos): |
+ import MemoryView, Options |
+ |
+ scope = self.scope |
+ |
+ if attribute == 'shape': |
+ scope.declare_var('shape', |
+ c_array_type(c_py_ssize_t_type, |
+ Options.buffer_max_dims), |
+ pos, |
+ cname='shape', |
+ is_cdef=1) |
+ |
+ elif attribute == 'strides': |
+ scope.declare_var('strides', |
+ c_array_type(c_py_ssize_t_type, |
+ Options.buffer_max_dims), |
+ pos, |
+ cname='strides', |
+ is_cdef=1) |
+ |
+ elif attribute == 'suboffsets': |
+ scope.declare_var('suboffsets', |
+ c_array_type(c_py_ssize_t_type, |
+ Options.buffer_max_dims), |
+ pos, |
+ cname='suboffsets', |
+ is_cdef=1) |
+ |
+ elif attribute in ("copy", "copy_fortran"): |
+ ndim = len(self.axes) |
+ |
+ to_axes_c = [('direct', 'contig')] |
+ to_axes_f = [('direct', 'contig')] |
+ if ndim - 1: |
+ to_axes_c = [('direct', 'follow')]*(ndim-1) + to_axes_c |
+ to_axes_f = to_axes_f + [('direct', 'follow')]*(ndim-1) |
+ |
+ to_memview_c = MemoryViewSliceType(self.dtype, to_axes_c) |
+ to_memview_f = MemoryViewSliceType(self.dtype, to_axes_f) |
+ |
+ for to_memview, cython_name in [(to_memview_c, "copy"), |
+ (to_memview_f, "copy_fortran")]: |
+ entry = scope.declare_cfunction(cython_name, |
+ CFuncType(self, [CFuncTypeArg("memviewslice", self, None)]), |
+ pos=pos, |
+ defining=1, |
+ cname=MemoryView.copy_c_or_fortran_cname(to_memview)) |
+ |
+ #entry.utility_code_definition = \ |
+ env.use_utility_code(MemoryView.get_copy_new_utility(pos, self, to_memview)) |
+ |
+ MemoryView.use_cython_array_utility_code(env) |
+ |
+ elif attribute in ("is_c_contig", "is_f_contig"): |
+ # is_c_contig and is_f_contig functions |
+ for (c_or_f, cython_name) in (('c', 'is_c_contig'), ('f', 'is_f_contig')): |
+ |
+ is_contig_name = \ |
+ MemoryView.get_is_contig_func_name(c_or_f, self.ndim) |
+ |
+ cfunctype = CFuncType( |
+ return_type=c_bint_type, |
+ args=[CFuncTypeArg("memviewslice", self, None)], |
+ exception_value="-1", |
+ ) |
+ |
+ entry = scope.declare_cfunction(cython_name, |
+ cfunctype, |
+ pos=pos, |
+ defining=1, |
+ cname=is_contig_name) |
+ |
+ entry.utility_code_definition = MemoryView.get_is_contig_utility( |
+ attribute == 'is_c_contig', self.ndim) |
+ |
+ return True |
+ |
+ def specialization_suffix(self): |
+ return "%s_%s" % (self.axes_to_name(), self.dtype_name) |
+ |
+ def can_coerce_to_pyobject(self, env): |
+ return True |
+ |
+ def check_for_null_code(self, cname): |
+ return cname + '.memview' |
+ |
+ def create_from_py_utility_code(self, env): |
+ import MemoryView, Buffer |
+ |
+ # We don't have 'code', so use a LazyUtilityCode with a callback. |
+ def lazy_utility_callback(code): |
+ context['dtype_typeinfo'] = Buffer.get_type_information_cname( |
+ code, self.dtype) |
+ return TempitaUtilityCode.load( |
+ "ObjectToMemviewSlice", "MemoryView_C.c", context=context) |
+ |
+ env.use_utility_code(Buffer.acquire_utility_code) |
+ env.use_utility_code(MemoryView.memviewslice_init_code) |
+ env.use_utility_code(LazyUtilityCode(lazy_utility_callback)) |
+ |
+ if self.is_c_contig: |
+ c_or_f_flag = "__Pyx_IS_C_CONTIG" |
+ elif self.is_f_contig: |
+ c_or_f_flag = "__Pyx_IS_F_CONTIG" |
+ else: |
+ c_or_f_flag = "0" |
+ |
+ suffix = self.specialization_suffix() |
+ funcname = "__Pyx_PyObject_to_MemoryviewSlice_" + suffix |
+ |
+ context = dict( |
+ MemoryView.context, |
+ buf_flag = self.flags, |
+ ndim = self.ndim, |
+ axes_specs = ', '.join(self.axes_to_code()), |
+ dtype_typedecl = self.dtype.declaration_code(""), |
+ struct_nesting_depth = self.dtype.struct_nesting_depth(), |
+ c_or_f_flag = c_or_f_flag, |
+ funcname = funcname, |
+ ) |
+ |
+ self.from_py_function = funcname |
+ return True |
+ |
+ def create_to_py_utility_code(self, env): |
+ return True |
+ |
+ def get_to_py_function(self, env, obj): |
+ to_py_func, from_py_func = self.dtype_object_conversion_funcs(env) |
+ to_py_func = "(PyObject *(*)(char *)) " + to_py_func |
+ from_py_func = "(int (*)(char *, PyObject *)) " + from_py_func |
+ |
+ tup = (obj.result(), self.ndim, to_py_func, from_py_func, |
+ self.dtype.is_pyobject) |
+ return "__pyx_memoryview_fromslice(%s, %s, %s, %s, %d);" % tup |
+ |
+ def dtype_object_conversion_funcs(self, env): |
+ get_function = "__pyx_memview_get_%s" % self.dtype_name |
+ set_function = "__pyx_memview_set_%s" % self.dtype_name |
+ |
+ context = dict( |
+ get_function = get_function, |
+ set_function = set_function, |
+ ) |
+ |
+ if self.dtype.is_pyobject: |
+ utility_name = "MemviewObjectToObject" |
+ else: |
+ to_py = self.dtype.create_to_py_utility_code(env) |
+ from_py = self.dtype.create_from_py_utility_code(env) |
+ if not (to_py or from_py): |
+ return "NULL", "NULL" |
+ |
+ if not self.dtype.to_py_function: |
+ get_function = "NULL" |
+ |
+ if not self.dtype.from_py_function: |
+ set_function = "NULL" |
+ |
+ utility_name = "MemviewDtypeToObject" |
+ error_condition = (self.dtype.error_condition('value') or |
+ 'PyErr_Occurred()') |
+ context.update( |
+ to_py_function = self.dtype.to_py_function, |
+ from_py_function = self.dtype.from_py_function, |
+ dtype = self.dtype.declaration_code(""), |
+ error_condition = error_condition, |
+ ) |
+ |
+ utility = TempitaUtilityCode.load( |
+ utility_name, "MemoryView_C.c", context=context) |
+ env.use_utility_code(utility) |
+ return get_function, set_function |
+ |
+ def axes_to_code(self): |
+ """Return a list of code constants for each axis""" |
+ import MemoryView |
+ d = MemoryView._spec_to_const |
+ return ["(%s | %s)" % (d[a], d[p]) for a, p in self.axes] |
+ |
+ def axes_to_name(self): |
+ """Return an abbreviated name for our axes""" |
+ import MemoryView |
+ d = MemoryView._spec_to_abbrev |
+ return "".join(["%s%s" % (d[a], d[p]) for a, p in self.axes]) |
+ |
+ def error_condition(self, result_code): |
+ return "!%s.memview" % result_code |
+ |
+ def __str__(self): |
+ import MemoryView |
+ |
+ axes_code_list = [] |
+ for idx, (access, packing) in enumerate(self.axes): |
+ flag = MemoryView.get_memoryview_flag(access, packing) |
+ if flag == "strided": |
+ axes_code_list.append(":") |
+ else: |
+ if flag == 'contiguous': |
+ have_follow = [p for a, p in self.axes[idx - 1:idx + 2] |
+ if p == 'follow'] |
+ if have_follow or self.ndim == 1: |
+ flag = '1' |
+ |
+ axes_code_list.append("::" + flag) |
+ |
+ if self.dtype.is_pyobject: |
+ dtype_name = self.dtype.name |
+ else: |
+ dtype_name = self.dtype |
+ |
+ return "%s[%s]" % (dtype_name, ", ".join(axes_code_list)) |
+ |
+ def specialize(self, values): |
+ """This does not validate the base type!!""" |
+ dtype = self.dtype.specialize(values) |
+ if dtype is not self.dtype: |
+ return MemoryViewSliceType(dtype, self.axes) |
+ |
+ return self |
+ |
+ def cast_code(self, expr_code): |
+ return expr_code |
+ |
+ |
+class BufferType(BaseType): |
+ # |
+ # Delegates most attribute lookups to the base type. |
+ # (Anything not defined here or in the BaseType is delegated.) |
+ # |
+ # dtype PyrexType |
+ # ndim int |
+ # mode str |
+ # negative_indices bool |
+ # cast bool |
+ # is_buffer bool |
+ # writable bool |
+ |
+ is_buffer = 1 |
+ writable = True |
+ |
+ subtypes = ['dtype'] |
+ |
+ def __init__(self, base, dtype, ndim, mode, negative_indices, cast): |
+ self.base = base |
+ self.dtype = dtype |
+ self.ndim = ndim |
+ self.buffer_ptr_type = CPtrType(dtype) |
+ self.mode = mode |
+ self.negative_indices = negative_indices |
+ self.cast = cast |
+ |
+ def as_argument_type(self): |
+ return self |
+ |
+ def specialize(self, values): |
+ dtype = self.dtype.specialize(values) |
+ if dtype is not self.dtype: |
+ return BufferType(self.base, dtype, self.ndim, self.mode, |
+ self.negative_indices, self.cast) |
+ return self |
+ |
+ def __getattr__(self, name): |
+ return getattr(self.base, name) |
+ |
+ def __repr__(self): |
+ return "<BufferType %r>" % self.base |
+ |
+ def __str__(self): |
+ # avoid ', ', as fused functions split the signature string on ', ' |
+ cast_str = '' |
+ if self.cast: |
+ cast_str = ',cast=True' |
+ |
+ return "%s[%s,ndim=%d%s]" % (self.base, self.dtype, self.ndim, |
+ cast_str) |
+ |
+ def assignable_from(self, other_type): |
+ if other_type.is_buffer: |
+ return (self.same_as(other_type, compare_base=False) and |
+ self.base.assignable_from(other_type.base)) |
+ |
+ return self.base.assignable_from(other_type) |
+ |
+ def same_as(self, other_type, compare_base=True): |
+ if not other_type.is_buffer: |
+ return other_type.same_as(self.base) |
+ |
+ return (self.dtype.same_as(other_type.dtype) and |
+ self.ndim == other_type.ndim and |
+ self.mode == other_type.mode and |
+ self.cast == other_type.cast and |
+ (not compare_base or self.base.same_as(other_type.base))) |
+ |
+ |
+class PyObjectType(PyrexType): |
+ # |
+ # Base class for all Python object types (reference-counted). |
+ # |
+ # buffer_defaults dict or None Default options for bu |
+ |
+ name = "object" |
+ is_pyobject = 1 |
+ default_value = "0" |
+ buffer_defaults = None |
+ is_extern = False |
+ is_subclassed = False |
+ is_gc_simple = False |
+ |
+ def __str__(self): |
+ return "Python object" |
+ |
+ def __repr__(self): |
+ return "<PyObjectType>" |
+ |
+ def can_coerce_to_pyobject(self, env): |
+ return True |
+ |
+ def default_coerced_ctype(self): |
+ """The default C type that this Python type coerces to, or None.""" |
+ return None |
+ |
+ def assignable_from(self, src_type): |
+ # except for pointers, conversion will be attempted |
+ return not src_type.is_ptr or src_type.is_string or src_type.is_pyunicode_ptr |
+ |
+ def declaration_code(self, entity_code, |
+ for_display = 0, dll_linkage = None, pyrex = 0): |
+ if pyrex or for_display: |
+ base_code = "object" |
+ else: |
+ base_code = public_decl("PyObject", dll_linkage) |
+ entity_code = "*%s" % entity_code |
+ return self.base_declaration_code(base_code, entity_code) |
+ |
+ def as_pyobject(self, cname): |
+ if (not self.is_complete()) or self.is_extension_type: |
+ return "(PyObject *)" + cname |
+ else: |
+ return cname |
+ |
+ def py_type_name(self): |
+ return "object" |
+ |
+ def __lt__(self, other): |
+ """ |
+ Make sure we sort highest, as instance checking on py_type_name |
+ ('object') is always true |
+ """ |
+ return False |
+ |
+ def global_init_code(self, entry, code): |
+ code.put_init_var_to_py_none(entry, nanny=False) |
+ |
+ def check_for_null_code(self, cname): |
+ return cname |
+ |
+ |
+builtin_types_that_cannot_create_refcycles = set([ |
+ 'bool', 'int', 'long', 'float', 'complex', |
+ 'bytearray', 'bytes', 'unicode', 'str', 'basestring' |
+]) |
+ |
+ |
+class BuiltinObjectType(PyObjectType): |
+ # objstruct_cname string Name of PyObject struct |
+ |
+ is_builtin_type = 1 |
+ has_attributes = 1 |
+ base_type = None |
+ module_name = '__builtin__' |
+ |
+ # fields that let it look like an extension type |
+ vtabslot_cname = None |
+ vtabstruct_cname = None |
+ vtabptr_cname = None |
+ typedef_flag = True |
+ is_external = True |
+ |
+ def __init__(self, name, cname, objstruct_cname=None): |
+ self.name = name |
+ self.cname = cname |
+ self.typeptr_cname = "(&%s)" % cname |
+ self.objstruct_cname = objstruct_cname |
+ self.is_gc_simple = name in builtin_types_that_cannot_create_refcycles |
+ |
+ def set_scope(self, scope): |
+ self.scope = scope |
+ if scope: |
+ scope.parent_type = self |
+ |
+ def __str__(self): |
+ return "%s object" % self.name |
+ |
+ def __repr__(self): |
+ return "<%s>"% self.cname |
+ |
+ def default_coerced_ctype(self): |
+ if self.name in ('bytes', 'bytearray'): |
+ return c_char_ptr_type |
+ elif self.name == 'bool': |
+ return c_bint_type |
+ elif self.name == 'float': |
+ return c_double_type |
+ return None |
+ |
+ def assignable_from(self, src_type): |
+ if isinstance(src_type, BuiltinObjectType): |
+ if self.name == 'basestring': |
+ return src_type.name in ('str', 'unicode', 'basestring') |
+ else: |
+ return src_type.name == self.name |
+ elif src_type.is_extension_type: |
+ # FIXME: This is an ugly special case that we currently |
+ # keep supporting. It allows users to specify builtin |
+ # types as external extension types, while keeping them |
+ # compatible with the real builtin types. We already |
+ # generate a warning for it. Big TODO: remove! |
+ return (src_type.module_name == '__builtin__' and |
+ src_type.name == self.name) |
+ else: |
+ return True |
+ |
+ def typeobj_is_available(self): |
+ return True |
+ |
+ def attributes_known(self): |
+ return True |
+ |
+ def subtype_of(self, type): |
+ return type.is_pyobject and type.assignable_from(self) |
+ |
+ def type_check_function(self, exact=True): |
+ type_name = self.name |
+ if type_name == 'str': |
+ type_check = 'PyString_Check' |
+ elif type_name == 'basestring': |
+ type_check = '__Pyx_PyBaseString_Check' |
+ elif type_name == 'bytearray': |
+ type_check = 'PyByteArray_Check' |
+ elif type_name == 'frozenset': |
+ type_check = 'PyFrozenSet_Check' |
+ else: |
+ type_check = 'Py%s_Check' % type_name.capitalize() |
+ if exact and type_name not in ('bool', 'slice'): |
+ type_check += 'Exact' |
+ return type_check |
+ |
+ def isinstance_code(self, arg): |
+ return '%s(%s)' % (self.type_check_function(exact=False), arg) |
+ |
+ def type_test_code(self, arg, notnone=False, exact=True): |
+ type_check = self.type_check_function(exact=exact) |
+ check = 'likely(%s(%s))' % (type_check, arg) |
+ if not notnone: |
+ check += '||((%s) == Py_None)' % arg |
+ if self.name == 'basestring': |
+ name = '(PY_MAJOR_VERSION < 3 ? "basestring" : "str")' |
+ space_for_name = 16 |
+ else: |
+ name = '"%s"' % self.name |
+ # avoid wasting too much space but limit number of different format strings |
+ space_for_name = (len(self.name) // 16 + 1) * 16 |
+ error = '(PyErr_Format(PyExc_TypeError, "Expected %%.%ds, got %%.200s", %s, Py_TYPE(%s)->tp_name), 0)' % ( |
+ space_for_name, name, arg) |
+ return check + '||' + error |
+ |
+ def declaration_code(self, entity_code, |
+ for_display = 0, dll_linkage = None, pyrex = 0): |
+ if pyrex or for_display: |
+ base_code = self.name |
+ else: |
+ base_code = public_decl("PyObject", dll_linkage) |
+ entity_code = "*%s" % entity_code |
+ return self.base_declaration_code(base_code, entity_code) |
+ |
+ def cast_code(self, expr_code, to_object_struct = False): |
+ return "((%s*)%s)" % ( |
+ to_object_struct and self.objstruct_cname or "PyObject", # self.objstruct_cname may be None |
+ expr_code) |
+ |
+ def py_type_name(self): |
+ return self.name |
+ |
+ |
+ |
+class PyExtensionType(PyObjectType): |
+ # |
+ # A Python extension type. |
+ # |
+ # name string |
+ # scope CClassScope Attribute namespace |
+ # visibility string |
+ # typedef_flag boolean |
+ # base_type PyExtensionType or None |
+ # module_name string or None Qualified name of defining module |
+ # objstruct_cname string Name of PyObject struct |
+ # objtypedef_cname string Name of PyObject struct typedef |
+ # typeobj_cname string or None C code fragment referring to type object |
+ # typeptr_cname string or None Name of pointer to external type object |
+ # vtabslot_cname string Name of C method table member |
+ # vtabstruct_cname string Name of C method table struct |
+ # vtabptr_cname string Name of pointer to C method table |
+ # vtable_cname string Name of C method table definition |
+ # defered_declarations [thunk] Used to declare class hierarchies in order |
+ |
+ is_extension_type = 1 |
+ has_attributes = 1 |
+ |
+ objtypedef_cname = None |
+ |
+ def __init__(self, name, typedef_flag, base_type, is_external=0): |
+ self.name = name |
+ self.scope = None |
+ self.typedef_flag = typedef_flag |
+ if base_type is not None: |
+ base_type.is_subclassed = True |
+ self.base_type = base_type |
+ self.module_name = None |
+ self.objstruct_cname = None |
+ self.typeobj_cname = None |
+ self.typeptr_cname = None |
+ self.vtabslot_cname = None |
+ self.vtabstruct_cname = None |
+ self.vtabptr_cname = None |
+ self.vtable_cname = None |
+ self.is_external = is_external |
+ self.defered_declarations = [] |
+ |
+ def set_scope(self, scope): |
+ self.scope = scope |
+ if scope: |
+ scope.parent_type = self |
+ |
+ def needs_nonecheck(self): |
+ return True |
+ |
+ def subtype_of_resolved_type(self, other_type): |
+ if other_type.is_extension_type or other_type.is_builtin_type: |
+ return self is other_type or ( |
+ self.base_type and self.base_type.subtype_of(other_type)) |
+ else: |
+ return other_type is py_object_type |
+ |
+ def typeobj_is_available(self): |
+ # Do we have a pointer to the type object? |
+ return self.typeptr_cname |
+ |
+ def typeobj_is_imported(self): |
+ # If we don't know the C name of the type object but we do |
+ # know which module it's defined in, it will be imported. |
+ return self.typeobj_cname is None and self.module_name is not None |
+ |
+ def assignable_from(self, src_type): |
+ if self == src_type: |
+ return True |
+ if isinstance(src_type, PyExtensionType): |
+ if src_type.base_type is not None: |
+ return self.assignable_from(src_type.base_type) |
+ if isinstance(src_type, BuiltinObjectType): |
+ # FIXME: This is an ugly special case that we currently |
+ # keep supporting. It allows users to specify builtin |
+ # types as external extension types, while keeping them |
+ # compatible with the real builtin types. We already |
+ # generate a warning for it. Big TODO: remove! |
+ return (self.module_name == '__builtin__' and |
+ self.name == src_type.name) |
+ return False |
+ |
+ def declaration_code(self, entity_code, |
+ for_display = 0, dll_linkage = None, pyrex = 0, deref = 0): |
+ if pyrex or for_display: |
+ base_code = self.name |
+ else: |
+ if self.typedef_flag: |
+ objstruct = self.objstruct_cname |
+ else: |
+ objstruct = "struct %s" % self.objstruct_cname |
+ base_code = public_decl(objstruct, dll_linkage) |
+ if deref: |
+ assert not entity_code |
+ else: |
+ entity_code = "*%s" % entity_code |
+ return self.base_declaration_code(base_code, entity_code) |
+ |
+ def type_test_code(self, py_arg, notnone=False): |
+ |
+ none_check = "((%s) == Py_None)" % py_arg |
+ type_check = "likely(__Pyx_TypeTest(%s, %s))" % ( |
+ py_arg, self.typeptr_cname) |
+ if notnone: |
+ return type_check |
+ else: |
+ return "likely(%s || %s)" % (none_check, type_check) |
+ |
+ def attributes_known(self): |
+ return self.scope is not None |
+ |
+ def __str__(self): |
+ return self.name |
+ |
+ def __repr__(self): |
+ return "<PyExtensionType %s%s>" % (self.scope.class_name, |
+ ("", " typedef")[self.typedef_flag]) |
+ |
+ def py_type_name(self): |
+ if not self.module_name: |
+ return self.name |
+ |
+ return "__import__(%r, None, None, ['']).%s" % (self.module_name, |
+ self.name) |
+ |
+class CType(PyrexType): |
+ # |
+ # Base class for all C types (non-reference-counted). |
+ # |
+ # to_py_function string C function for converting to Python object |
+ # from_py_function string C function for constructing from Python object |
+ # |
+ |
+ to_py_function = None |
+ from_py_function = None |
+ exception_value = None |
+ exception_check = 1 |
+ |
+ def create_to_py_utility_code(self, env): |
+ return self.to_py_function is not None |
+ |
+ def create_from_py_utility_code(self, env): |
+ return self.from_py_function is not None |
+ |
+ def can_coerce_to_pyobject(self, env): |
+ return self.create_to_py_utility_code(env) |
+ |
+ def error_condition(self, result_code): |
+ conds = [] |
+ if self.is_string or self.is_pyunicode_ptr: |
+ conds.append("(!%s)" % result_code) |
+ elif self.exception_value is not None: |
+ conds.append("(%s == (%s)%s)" % (result_code, self.sign_and_name(), self.exception_value)) |
+ if self.exception_check: |
+ conds.append("PyErr_Occurred()") |
+ if len(conds) > 0: |
+ return " && ".join(conds) |
+ else: |
+ return 0 |
+ |
+ |
+class CConstType(BaseType): |
+ |
+ is_const = 1 |
+ |
+ def __init__(self, const_base_type): |
+ self.const_base_type = const_base_type |
+ if const_base_type.has_attributes and const_base_type.scope is not None: |
+ import Symtab |
+ self.scope = Symtab.CConstScope(const_base_type.scope) |
+ |
+ def __repr__(self): |
+ return "<CConstType %s>" % repr(self.const_base_type) |
+ |
+ def __str__(self): |
+ return self.declaration_code("", for_display=1) |
+ |
+ def declaration_code(self, entity_code, |
+ for_display = 0, dll_linkage = None, pyrex = 0): |
+ return self.const_base_type.declaration_code("const %s" % entity_code, for_display, dll_linkage, pyrex) |
+ |
+ def specialize(self, values): |
+ base_type = self.const_base_type.specialize(values) |
+ if base_type == self.const_base_type: |
+ return self |
+ else: |
+ return CConstType(base_type) |
+ |
+ def deduce_template_params(self, actual): |
+ return self.const_base_type.deduce_template_params(actual) |
+ |
+ def create_to_py_utility_code(self, env): |
+ if self.const_base_type.create_to_py_utility_code(env): |
+ self.to_py_function = self.const_base_type.to_py_function |
+ return True |
+ |
+ def __getattr__(self, name): |
+ return getattr(self.const_base_type, name) |
+ |
+ |
+class FusedType(CType): |
+ """ |
+ Represents a Fused Type. All it needs to do is keep track of the types |
+ it aggregates, as it will be replaced with its specific version wherever |
+ needed. |
+ |
+ See http://wiki.cython.org/enhancements/fusedtypes |
+ |
+ types [PyrexType] is the list of types to be fused |
+ name str the name of the ctypedef |
+ """ |
+ |
+ is_fused = 1 |
+ exception_check = 0 |
+ |
+ def __init__(self, types, name=None): |
+ self.types = types |
+ self.name = name |
+ |
+ def declaration_code(self, entity_code, for_display = 0, |
+ dll_linkage = None, pyrex = 0): |
+ if pyrex or for_display: |
+ return self.name |
+ |
+ raise Exception("This may never happen, please report a bug") |
+ |
+ def __repr__(self): |
+ return 'FusedType(name=%r)' % self.name |
+ |
+ def specialize(self, values): |
+ return values[self] |
+ |
+ def get_fused_types(self, result=None, seen=None): |
+ if result is None: |
+ return [self] |
+ |
+ if self not in seen: |
+ result.append(self) |
+ seen.add(self) |
+ |
+ |
+class CVoidType(CType): |
+ # |
+ # C "void" type |
+ # |
+ |
+ is_void = 1 |
+ |
+ def __repr__(self): |
+ return "<CVoidType>" |
+ |
+ def declaration_code(self, entity_code, |
+ for_display = 0, dll_linkage = None, pyrex = 0): |
+ if pyrex or for_display: |
+ base_code = "void" |
+ else: |
+ base_code = public_decl("void", dll_linkage) |
+ return self.base_declaration_code(base_code, entity_code) |
+ |
+ def is_complete(self): |
+ return 0 |
+ |
+class InvisibleVoidType(CVoidType): |
+ # |
+ # For use with C++ constructors and destructors return types. |
+ # Acts like void, but does not print out a declaration. |
+ # |
+ def declaration_code(self, entity_code, |
+ for_display = 0, dll_linkage = None, pyrex = 0): |
+ if pyrex or for_display: |
+ base_code = "[void]" |
+ else: |
+ base_code = public_decl("", dll_linkage) |
+ return self.base_declaration_code(base_code, entity_code) |
+ |
+ |
+class CNumericType(CType): |
+ # |
+ # Base class for all C numeric types. |
+ # |
+ # rank integer Relative size |
+ # signed integer 0 = unsigned, 1 = unspecified, 2 = explicitly signed |
+ # |
+ |
+ is_numeric = 1 |
+ default_value = "0" |
+ has_attributes = True |
+ scope = None |
+ |
+ sign_words = ("unsigned ", "", "signed ") |
+ |
+ def __init__(self, rank, signed = 1): |
+ self.rank = rank |
+ self.signed = signed |
+ |
+ def sign_and_name(self): |
+ s = self.sign_words[self.signed] |
+ n = rank_to_type_name[self.rank] |
+ return s + n |
+ |
+ def __repr__(self): |
+ return "<CNumericType %s>" % self.sign_and_name() |
+ |
+ def declaration_code(self, entity_code, |
+ for_display = 0, dll_linkage = None, pyrex = 0): |
+ type_name = self.sign_and_name() |
+ if pyrex or for_display: |
+ base_code = type_name.replace('PY_LONG_LONG', 'long long') |
+ else: |
+ base_code = public_decl(type_name, dll_linkage) |
+ return self.base_declaration_code(base_code, entity_code) |
+ |
+ def attributes_known(self): |
+ if self.scope is None: |
+ import Symtab |
+ self.scope = scope = Symtab.CClassScope( |
+ '', |
+ None, |
+ visibility="extern") |
+ scope.parent_type = self |
+ scope.directives = {} |
+ scope.declare_cfunction( |
+ "conjugate", |
+ CFuncType(self, [CFuncTypeArg("self", self, None)], nogil=True), |
+ pos=None, |
+ defining=1, |
+ cname=" ") |
+ return True |
+ |
+ def __lt__(self, other): |
+ """Sort based on rank, preferring signed over unsigned""" |
+ if other.is_numeric: |
+ return self.rank > other.rank and self.signed >= other.signed |
+ |
+ # Prefer numeric types over others |
+ return True |
+ |
+ def py_type_name(self): |
+ if self.rank <= 4: |
+ return "(int, long)" |
+ return "float" |
+ |
+ |
+class ForbidUseClass: |
+ def __repr__(self): |
+ raise RuntimeError() |
+ def __str__(self): |
+ raise RuntimeError() |
+ForbidUse = ForbidUseClass() |
+ |
+ |
+class CIntType(CNumericType): |
+ |
+ is_int = 1 |
+ typedef_flag = 0 |
+ to_py_function = None |
+ from_py_function = None |
+ exception_value = -1 |
+ |
+ def create_to_py_utility_code(self, env): |
+ if type(self).to_py_function is None: |
+ self.to_py_function = "__Pyx_PyInt_From_" + self.specialization_name() |
+ env.use_utility_code(TempitaUtilityCode.load( |
+ "CIntToPy", "TypeConversion.c", |
+ context={"TYPE": self.declaration_code(''), |
+ "TO_PY_FUNCTION": self.to_py_function})) |
+ return True |
+ |
+ def create_from_py_utility_code(self, env): |
+ if type(self).from_py_function is None: |
+ self.from_py_function = "__Pyx_PyInt_As_" + self.specialization_name() |
+ env.use_utility_code(TempitaUtilityCode.load( |
+ "CIntFromPy", "TypeConversion.c", |
+ context={"TYPE": self.declaration_code(''), |
+ "FROM_PY_FUNCTION": self.from_py_function})) |
+ return True |
+ |
+ def get_to_py_type_conversion(self): |
+ if self.rank < list(rank_to_type_name).index('int'): |
+ # This assumes sizeof(short) < sizeof(int) |
+ return "PyInt_FromLong" |
+ else: |
+ # Py{Int|Long}_From[Unsigned]Long[Long] |
+ Prefix = "Int" |
+ SignWord = "" |
+ TypeName = "Long" |
+ if not self.signed: |
+ Prefix = "Long" |
+ SignWord = "Unsigned" |
+ if self.rank >= list(rank_to_type_name).index('PY_LONG_LONG'): |
+ Prefix = "Long" |
+ TypeName = "LongLong" |
+ return "Py%s_From%s%s" % (Prefix, SignWord, TypeName) |
+ |
+ def get_from_py_type_conversion(self): |
+ type_name = rank_to_type_name[self.rank] |
+ type_name = type_name.replace("PY_LONG_LONG", "long long") |
+ TypeName = type_name.title().replace(" ", "") |
+ SignWord = self.sign_words[self.signed].strip().title() |
+ if self.rank >= list(rank_to_type_name).index('long'): |
+ utility_code = c_long_from_py_function |
+ else: |
+ utility_code = c_int_from_py_function |
+ utility_code.specialize(self, |
+ SignWord=SignWord, |
+ TypeName=TypeName) |
+ func_name = "__Pyx_PyInt_As%s%s" % (SignWord, TypeName) |
+ return func_name |
+ |
+ def assignable_from_resolved_type(self, src_type): |
+ return src_type.is_int or src_type.is_enum or src_type is error_type |
+ |
+ def invalid_value(self): |
+ if rank_to_type_name[int(self.rank)] == 'char': |
+ return "'?'" |
+ else: |
+ # We do not really know the size of the type, so return |
+ # a 32-bit literal and rely on casting to final type. It will |
+ # be negative for signed ints, which is good. |
+ return "0xbad0bad0" |
+ |
+ def overflow_check_binop(self, binop, env, const_rhs=False): |
+ env.use_utility_code(UtilityCode.load("Common", "Overflow.c")) |
+ type = self.declaration_code("") |
+ name = self.specialization_name() |
+ if binop == "lshift": |
+ env.use_utility_code(TempitaUtilityCode.load( |
+ "LeftShift", "Overflow.c", |
+ context={'TYPE': type, 'NAME': name, 'SIGNED': self.signed})) |
+ else: |
+ if const_rhs: |
+ binop += "_const" |
+ if type in ('int', 'long', 'long long'): |
+ env.use_utility_code(TempitaUtilityCode.load( |
+ "BaseCaseSigned", "Overflow.c", |
+ context={'INT': type, 'NAME': name})) |
+ elif type in ('unsigned int', 'unsigned long', 'unsigned long long'): |
+ env.use_utility_code(TempitaUtilityCode.load( |
+ "BaseCaseUnsigned", "Overflow.c", |
+ context={'UINT': type, 'NAME': name})) |
+ elif self.rank <= 1: |
+ # sizeof(short) < sizeof(int) |
+ return "__Pyx_%s_%s_no_overflow" % (binop, name) |
+ else: |
+ _load_overflow_base(env) |
+ env.use_utility_code(TempitaUtilityCode.load( |
+ "SizeCheck", "Overflow.c", |
+ context={'TYPE': type, 'NAME': name})) |
+ env.use_utility_code(TempitaUtilityCode.load( |
+ "Binop", "Overflow.c", |
+ context={'TYPE': type, 'NAME': name, 'BINOP': binop})) |
+ return "__Pyx_%s_%s_checking_overflow" % (binop, name) |
+ |
+def _load_overflow_base(env): |
+ env.use_utility_code(UtilityCode.load("Common", "Overflow.c")) |
+ for type in ('int', 'long', 'long long'): |
+ env.use_utility_code(TempitaUtilityCode.load( |
+ "BaseCaseSigned", "Overflow.c", |
+ context={'INT': type, 'NAME': type.replace(' ', '_')})) |
+ for type in ('unsigned int', 'unsigned long', 'unsigned long long'): |
+ env.use_utility_code(TempitaUtilityCode.load( |
+ "BaseCaseUnsigned", "Overflow.c", |
+ context={'UINT': type, 'NAME': type.replace(' ', '_')})) |
+ |
+ |
+class CAnonEnumType(CIntType): |
+ |
+ is_enum = 1 |
+ |
+ def sign_and_name(self): |
+ return 'int' |
+ |
+ |
+class CReturnCodeType(CIntType): |
+ |
+ to_py_function = "__Pyx_Owned_Py_None" |
+ |
+ is_returncode = True |
+ exception_check = False |
+ |
+ |
+class CBIntType(CIntType): |
+ |
+ to_py_function = "__Pyx_PyBool_FromLong" |
+ from_py_function = "__Pyx_PyObject_IsTrue" |
+ exception_check = 1 # for C++ bool |
+ |
+ def declaration_code(self, entity_code, |
+ for_display = 0, dll_linkage = None, pyrex = 0): |
+ if pyrex or for_display: |
+ base_code = 'bool' |
+ else: |
+ base_code = public_decl('int', dll_linkage) |
+ return self.base_declaration_code(base_code, entity_code) |
+ |
+ def __repr__(self): |
+ return "<CNumericType bint>" |
+ |
+ def __str__(self): |
+ return 'bint' |
+ |
+ def py_type_name(self): |
+ return "bool" |
+ |
+ |
+class CPyUCS4IntType(CIntType): |
+ # Py_UCS4 |
+ |
+ is_unicode_char = True |
+ |
+ # Py_UCS4 coerces from and to single character unicode strings (or |
+ # at most two characters on 16bit Unicode builds), but we also |
+ # allow Python integers as input. The value range for Py_UCS4 |
+ # is 0..1114111, which is checked when converting from an integer |
+ # value. |
+ |
+ to_py_function = "PyUnicode_FromOrdinal" |
+ from_py_function = "__Pyx_PyObject_AsPy_UCS4" |
+ |
+ def create_from_py_utility_code(self, env): |
+ env.use_utility_code(UtilityCode.load_cached("ObjectAsUCS4", "TypeConversion.c")) |
+ return True |
+ |
+ def sign_and_name(self): |
+ return "Py_UCS4" |
+ |
+ |
+class CPyUnicodeIntType(CIntType): |
+ # Py_UNICODE |
+ |
+ is_unicode_char = True |
+ |
+ # Py_UNICODE coerces from and to single character unicode strings, |
+ # but we also allow Python integers as input. The value range for |
+ # Py_UNICODE is 0..1114111, which is checked when converting from |
+ # an integer value. |
+ |
+ to_py_function = "PyUnicode_FromOrdinal" |
+ from_py_function = "__Pyx_PyObject_AsPy_UNICODE" |
+ |
+ def create_from_py_utility_code(self, env): |
+ env.use_utility_code(UtilityCode.load_cached("ObjectAsPyUnicode", "TypeConversion.c")) |
+ return True |
+ |
+ def sign_and_name(self): |
+ return "Py_UNICODE" |
+ |
+ |
+class CPyHashTType(CIntType): |
+ |
+ to_py_function = "__Pyx_PyInt_FromHash_t" |
+ from_py_function = "__Pyx_PyInt_AsHash_t" |
+ |
+ def sign_and_name(self): |
+ return "Py_hash_t" |
+ |
+class CPySSizeTType(CIntType): |
+ |
+ to_py_function = "PyInt_FromSsize_t" |
+ from_py_function = "__Pyx_PyIndex_AsSsize_t" |
+ |
+ def sign_and_name(self): |
+ return "Py_ssize_t" |
+ |
+class CSSizeTType(CIntType): |
+ |
+ to_py_function = "PyInt_FromSsize_t" |
+ from_py_function = "PyInt_AsSsize_t" |
+ |
+ def sign_and_name(self): |
+ return "Py_ssize_t" |
+ |
+class CSizeTType(CIntType): |
+ |
+ to_py_function = "__Pyx_PyInt_FromSize_t" |
+ |
+ def sign_and_name(self): |
+ return "size_t" |
+ |
+class CPtrdiffTType(CIntType): |
+ |
+ def sign_and_name(self): |
+ return "ptrdiff_t" |
+ |
+ |
+class CFloatType(CNumericType): |
+ |
+ is_float = 1 |
+ to_py_function = "PyFloat_FromDouble" |
+ from_py_function = "__pyx_PyFloat_AsDouble" |
+ |
+ exception_value = -1 |
+ |
+ def __init__(self, rank, math_h_modifier = ''): |
+ CNumericType.__init__(self, rank, 1) |
+ self.math_h_modifier = math_h_modifier |
+ if rank == RANK_FLOAT: |
+ self.from_py_function = "__pyx_PyFloat_AsFloat" |
+ |
+ def assignable_from_resolved_type(self, src_type): |
+ return (src_type.is_numeric and not src_type.is_complex) or src_type is error_type |
+ |
+ def invalid_value(self): |
+ return Naming.PYX_NAN |
+ |
+class CComplexType(CNumericType): |
+ |
+ is_complex = 1 |
+ to_py_function = "__pyx_PyComplex_FromComplex" |
+ has_attributes = 1 |
+ scope = None |
+ |
+ def __init__(self, real_type): |
+ while real_type.is_typedef and not real_type.typedef_is_external: |
+ real_type = real_type.typedef_base_type |
+ if real_type.is_typedef and real_type.typedef_is_external: |
+ # The below is not actually used: Coercions are currently disabled |
+ # so that complex types of external types can not be created |
+ self.funcsuffix = "_%s" % real_type.specialization_name() |
+ elif hasattr(real_type, 'math_h_modifier'): |
+ self.funcsuffix = real_type.math_h_modifier |
+ else: |
+ self.funcsuffix = "_%s" % real_type.specialization_name() |
+ |
+ self.real_type = real_type |
+ CNumericType.__init__(self, real_type.rank + 0.5, real_type.signed) |
+ self.binops = {} |
+ self.from_parts = "%s_from_parts" % self.specialization_name() |
+ self.default_value = "%s(0, 0)" % self.from_parts |
+ |
+ def __eq__(self, other): |
+ if isinstance(self, CComplexType) and isinstance(other, CComplexType): |
+ return self.real_type == other.real_type |
+ else: |
+ return False |
+ |
+ def __ne__(self, other): |
+ if isinstance(self, CComplexType) and isinstance(other, CComplexType): |
+ return self.real_type != other.real_type |
+ else: |
+ return True |
+ |
+ def __lt__(self, other): |
+ if isinstance(self, CComplexType) and isinstance(other, CComplexType): |
+ return self.real_type < other.real_type |
+ else: |
+ # this is arbitrary, but it makes sure we always have |
+ # *some* kind of order |
+ return False |
+ |
+ def __hash__(self): |
+ return ~hash(self.real_type) |
+ |
+ def declaration_code(self, entity_code, |
+ for_display = 0, dll_linkage = None, pyrex = 0): |
+ if pyrex or for_display: |
+ real_code = self.real_type.declaration_code("", for_display, dll_linkage, pyrex) |
+ base_code = "%s complex" % real_code |
+ else: |
+ base_code = public_decl(self.sign_and_name(), dll_linkage) |
+ return self.base_declaration_code(base_code, entity_code) |
+ |
+ def sign_and_name(self): |
+ real_type_name = self.real_type.specialization_name() |
+ real_type_name = real_type_name.replace('long__double','long_double') |
+ real_type_name = real_type_name.replace('PY_LONG_LONG','long_long') |
+ return Naming.type_prefix + real_type_name + "_complex" |
+ |
+ def assignable_from(self, src_type): |
+ # Temporary hack/feature disabling, see #441 |
+ if (not src_type.is_complex and src_type.is_numeric and src_type.is_typedef |
+ and src_type.typedef_is_external): |
+ return False |
+ else: |
+ return super(CComplexType, self).assignable_from(src_type) |
+ |
+ def assignable_from_resolved_type(self, src_type): |
+ return (src_type.is_complex and self.real_type.assignable_from_resolved_type(src_type.real_type) |
+ or src_type.is_numeric and self.real_type.assignable_from_resolved_type(src_type) |
+ or src_type is error_type) |
+ |
+ def attributes_known(self): |
+ if self.scope is None: |
+ import Symtab |
+ self.scope = scope = Symtab.CClassScope( |
+ '', |
+ None, |
+ visibility="extern") |
+ scope.parent_type = self |
+ scope.directives = {} |
+ scope.declare_var("real", self.real_type, None, cname="real", is_cdef=True) |
+ scope.declare_var("imag", self.real_type, None, cname="imag", is_cdef=True) |
+ scope.declare_cfunction( |
+ "conjugate", |
+ CFuncType(self, [CFuncTypeArg("self", self, None)], nogil=True), |
+ pos=None, |
+ defining=1, |
+ cname="__Pyx_c_conj%s" % self.funcsuffix) |
+ |
+ return True |
+ |
+ def create_declaration_utility_code(self, env): |
+ # This must always be run, because a single CComplexType instance can be shared |
+ # across multiple compilations (the one created in the module scope) |
+ env.use_utility_code(complex_header_utility_code) |
+ env.use_utility_code(complex_real_imag_utility_code) |
+ for utility_code in (complex_type_utility_code, |
+ complex_from_parts_utility_code, |
+ complex_arithmetic_utility_code): |
+ env.use_utility_code( |
+ utility_code.specialize( |
+ self, |
+ real_type = self.real_type.declaration_code(''), |
+ m = self.funcsuffix, |
+ is_float = self.real_type.is_float)) |
+ return True |
+ |
+ def create_to_py_utility_code(self, env): |
+ env.use_utility_code(complex_real_imag_utility_code) |
+ env.use_utility_code(complex_to_py_utility_code) |
+ return True |
+ |
+ def create_from_py_utility_code(self, env): |
+ self.real_type.create_from_py_utility_code(env) |
+ |
+ for utility_code in (complex_from_parts_utility_code, |
+ complex_from_py_utility_code): |
+ env.use_utility_code( |
+ utility_code.specialize( |
+ self, |
+ real_type = self.real_type.declaration_code(''), |
+ m = self.funcsuffix, |
+ is_float = self.real_type.is_float)) |
+ self.from_py_function = "__Pyx_PyComplex_As_" + self.specialization_name() |
+ return True |
+ |
+ def lookup_op(self, nargs, op): |
+ try: |
+ return self.binops[nargs, op] |
+ except KeyError: |
+ pass |
+ try: |
+ op_name = complex_ops[nargs, op] |
+ self.binops[nargs, op] = func_name = "__Pyx_c_%s%s" % (op_name, self.funcsuffix) |
+ return func_name |
+ except KeyError: |
+ return None |
+ |
+ def unary_op(self, op): |
+ return self.lookup_op(1, op) |
+ |
+ def binary_op(self, op): |
+ return self.lookup_op(2, op) |
+ |
+ def py_type_name(self): |
+ return "complex" |
+ |
+ def cast_code(self, expr_code): |
+ return expr_code |
+ |
+complex_ops = { |
+ (1, '-'): 'neg', |
+ (1, 'zero'): 'is_zero', |
+ (2, '+'): 'sum', |
+ (2, '-'): 'diff', |
+ (2, '*'): 'prod', |
+ (2, '/'): 'quot', |
+ (2, '=='): 'eq', |
+} |
+ |
+complex_header_utility_code = UtilityCode( |
+proto_block='h_code', |
+proto=""" |
+#if !defined(CYTHON_CCOMPLEX) |
+ #if defined(__cplusplus) |
+ #define CYTHON_CCOMPLEX 1 |
+ #elif defined(_Complex_I) |
+ #define CYTHON_CCOMPLEX 1 |
+ #else |
+ #define CYTHON_CCOMPLEX 0 |
+ #endif |
+#endif |
+ |
+#if CYTHON_CCOMPLEX |
+ #ifdef __cplusplus |
+ #include <complex> |
+ #else |
+ #include <complex.h> |
+ #endif |
+#endif |
+ |
+#if CYTHON_CCOMPLEX && !defined(__cplusplus) && defined(__sun__) && defined(__GNUC__) |
+ #undef _Complex_I |
+ #define _Complex_I 1.0fj |
+#endif |
+""") |
+ |
+complex_real_imag_utility_code = UtilityCode( |
+proto=""" |
+#if CYTHON_CCOMPLEX |
+ #ifdef __cplusplus |
+ #define __Pyx_CREAL(z) ((z).real()) |
+ #define __Pyx_CIMAG(z) ((z).imag()) |
+ #else |
+ #define __Pyx_CREAL(z) (__real__(z)) |
+ #define __Pyx_CIMAG(z) (__imag__(z)) |
+ #endif |
+#else |
+ #define __Pyx_CREAL(z) ((z).real) |
+ #define __Pyx_CIMAG(z) ((z).imag) |
+#endif |
+ |
+#if (defined(_WIN32) || defined(__clang__)) && defined(__cplusplus) && CYTHON_CCOMPLEX |
+ #define __Pyx_SET_CREAL(z,x) ((z).real(x)) |
+ #define __Pyx_SET_CIMAG(z,y) ((z).imag(y)) |
+#else |
+ #define __Pyx_SET_CREAL(z,x) __Pyx_CREAL(z) = (x) |
+ #define __Pyx_SET_CIMAG(z,y) __Pyx_CIMAG(z) = (y) |
+#endif |
+""") |
+ |
+complex_type_utility_code = UtilityCode( |
+proto_block='complex_type_declarations', |
+proto=""" |
+#if CYTHON_CCOMPLEX |
+ #ifdef __cplusplus |
+ typedef ::std::complex< %(real_type)s > %(type_name)s; |
+ #else |
+ typedef %(real_type)s _Complex %(type_name)s; |
+ #endif |
+#else |
+ typedef struct { %(real_type)s real, imag; } %(type_name)s; |
+#endif |
+""") |
+ |
+complex_from_parts_utility_code = UtilityCode( |
+proto_block='utility_code_proto', |
+proto=""" |
+static CYTHON_INLINE %(type)s %(type_name)s_from_parts(%(real_type)s, %(real_type)s); |
+""", |
+impl=""" |
+#if CYTHON_CCOMPLEX |
+ #ifdef __cplusplus |
+ static CYTHON_INLINE %(type)s %(type_name)s_from_parts(%(real_type)s x, %(real_type)s y) { |
+ return ::std::complex< %(real_type)s >(x, y); |
+ } |
+ #else |
+ static CYTHON_INLINE %(type)s %(type_name)s_from_parts(%(real_type)s x, %(real_type)s y) { |
+ return x + y*(%(type)s)_Complex_I; |
+ } |
+ #endif |
+#else |
+ static CYTHON_INLINE %(type)s %(type_name)s_from_parts(%(real_type)s x, %(real_type)s y) { |
+ %(type)s z; |
+ z.real = x; |
+ z.imag = y; |
+ return z; |
+ } |
+#endif |
+""") |
+ |
+complex_to_py_utility_code = UtilityCode( |
+proto=""" |
+#define __pyx_PyComplex_FromComplex(z) \\ |
+ PyComplex_FromDoubles((double)__Pyx_CREAL(z), \\ |
+ (double)__Pyx_CIMAG(z)) |
+""") |
+ |
+complex_from_py_utility_code = UtilityCode( |
+proto=""" |
+static %(type)s __Pyx_PyComplex_As_%(type_name)s(PyObject*); |
+""", |
+impl=""" |
+static %(type)s __Pyx_PyComplex_As_%(type_name)s(PyObject* o) { |
+ Py_complex cval; |
+#if CYTHON_COMPILING_IN_CPYTHON |
+ if (PyComplex_CheckExact(o)) |
+ cval = ((PyComplexObject *)o)->cval; |
+ else |
+#endif |
+ cval = PyComplex_AsCComplex(o); |
+ return %(type_name)s_from_parts( |
+ (%(real_type)s)cval.real, |
+ (%(real_type)s)cval.imag); |
+} |
+""") |
+ |
+complex_arithmetic_utility_code = UtilityCode( |
+proto=""" |
+#if CYTHON_CCOMPLEX |
+ #define __Pyx_c_eq%(m)s(a, b) ((a)==(b)) |
+ #define __Pyx_c_sum%(m)s(a, b) ((a)+(b)) |
+ #define __Pyx_c_diff%(m)s(a, b) ((a)-(b)) |
+ #define __Pyx_c_prod%(m)s(a, b) ((a)*(b)) |
+ #define __Pyx_c_quot%(m)s(a, b) ((a)/(b)) |
+ #define __Pyx_c_neg%(m)s(a) (-(a)) |
+ #ifdef __cplusplus |
+ #define __Pyx_c_is_zero%(m)s(z) ((z)==(%(real_type)s)0) |
+ #define __Pyx_c_conj%(m)s(z) (::std::conj(z)) |
+ #if %(is_float)s |
+ #define __Pyx_c_abs%(m)s(z) (::std::abs(z)) |
+ #define __Pyx_c_pow%(m)s(a, b) (::std::pow(a, b)) |
+ #endif |
+ #else |
+ #define __Pyx_c_is_zero%(m)s(z) ((z)==0) |
+ #define __Pyx_c_conj%(m)s(z) (conj%(m)s(z)) |
+ #if %(is_float)s |
+ #define __Pyx_c_abs%(m)s(z) (cabs%(m)s(z)) |
+ #define __Pyx_c_pow%(m)s(a, b) (cpow%(m)s(a, b)) |
+ #endif |
+ #endif |
+#else |
+ static CYTHON_INLINE int __Pyx_c_eq%(m)s(%(type)s, %(type)s); |
+ static CYTHON_INLINE %(type)s __Pyx_c_sum%(m)s(%(type)s, %(type)s); |
+ static CYTHON_INLINE %(type)s __Pyx_c_diff%(m)s(%(type)s, %(type)s); |
+ static CYTHON_INLINE %(type)s __Pyx_c_prod%(m)s(%(type)s, %(type)s); |
+ static CYTHON_INLINE %(type)s __Pyx_c_quot%(m)s(%(type)s, %(type)s); |
+ static CYTHON_INLINE %(type)s __Pyx_c_neg%(m)s(%(type)s); |
+ static CYTHON_INLINE int __Pyx_c_is_zero%(m)s(%(type)s); |
+ static CYTHON_INLINE %(type)s __Pyx_c_conj%(m)s(%(type)s); |
+ #if %(is_float)s |
+ static CYTHON_INLINE %(real_type)s __Pyx_c_abs%(m)s(%(type)s); |
+ static CYTHON_INLINE %(type)s __Pyx_c_pow%(m)s(%(type)s, %(type)s); |
+ #endif |
+#endif |
+""", |
+impl=""" |
+#if CYTHON_CCOMPLEX |
+#else |
+ static CYTHON_INLINE int __Pyx_c_eq%(m)s(%(type)s a, %(type)s b) { |
+ return (a.real == b.real) && (a.imag == b.imag); |
+ } |
+ static CYTHON_INLINE %(type)s __Pyx_c_sum%(m)s(%(type)s a, %(type)s b) { |
+ %(type)s z; |
+ z.real = a.real + b.real; |
+ z.imag = a.imag + b.imag; |
+ return z; |
+ } |
+ static CYTHON_INLINE %(type)s __Pyx_c_diff%(m)s(%(type)s a, %(type)s b) { |
+ %(type)s z; |
+ z.real = a.real - b.real; |
+ z.imag = a.imag - b.imag; |
+ return z; |
+ } |
+ static CYTHON_INLINE %(type)s __Pyx_c_prod%(m)s(%(type)s a, %(type)s b) { |
+ %(type)s z; |
+ z.real = a.real * b.real - a.imag * b.imag; |
+ z.imag = a.real * b.imag + a.imag * b.real; |
+ return z; |
+ } |
+ static CYTHON_INLINE %(type)s __Pyx_c_quot%(m)s(%(type)s a, %(type)s b) { |
+ %(type)s z; |
+ %(real_type)s denom = b.real * b.real + b.imag * b.imag; |
+ z.real = (a.real * b.real + a.imag * b.imag) / denom; |
+ z.imag = (a.imag * b.real - a.real * b.imag) / denom; |
+ return z; |
+ } |
+ static CYTHON_INLINE %(type)s __Pyx_c_neg%(m)s(%(type)s a) { |
+ %(type)s z; |
+ z.real = -a.real; |
+ z.imag = -a.imag; |
+ return z; |
+ } |
+ static CYTHON_INLINE int __Pyx_c_is_zero%(m)s(%(type)s a) { |
+ return (a.real == 0) && (a.imag == 0); |
+ } |
+ static CYTHON_INLINE %(type)s __Pyx_c_conj%(m)s(%(type)s a) { |
+ %(type)s z; |
+ z.real = a.real; |
+ z.imag = -a.imag; |
+ return z; |
+ } |
+ #if %(is_float)s |
+ static CYTHON_INLINE %(real_type)s __Pyx_c_abs%(m)s(%(type)s z) { |
+ #if !defined(HAVE_HYPOT) || defined(_MSC_VER) |
+ return sqrt%(m)s(z.real*z.real + z.imag*z.imag); |
+ #else |
+ return hypot%(m)s(z.real, z.imag); |
+ #endif |
+ } |
+ static CYTHON_INLINE %(type)s __Pyx_c_pow%(m)s(%(type)s a, %(type)s b) { |
+ %(type)s z; |
+ %(real_type)s r, lnr, theta, z_r, z_theta; |
+ if (b.imag == 0 && b.real == (int)b.real) { |
+ if (b.real < 0) { |
+ %(real_type)s denom = a.real * a.real + a.imag * a.imag; |
+ a.real = a.real / denom; |
+ a.imag = -a.imag / denom; |
+ b.real = -b.real; |
+ } |
+ switch ((int)b.real) { |
+ case 0: |
+ z.real = 1; |
+ z.imag = 0; |
+ return z; |
+ case 1: |
+ return a; |
+ case 2: |
+ z = __Pyx_c_prod%(m)s(a, a); |
+ return __Pyx_c_prod%(m)s(a, a); |
+ case 3: |
+ z = __Pyx_c_prod%(m)s(a, a); |
+ return __Pyx_c_prod%(m)s(z, a); |
+ case 4: |
+ z = __Pyx_c_prod%(m)s(a, a); |
+ return __Pyx_c_prod%(m)s(z, z); |
+ } |
+ } |
+ if (a.imag == 0) { |
+ if (a.real == 0) { |
+ return a; |
+ } |
+ r = a.real; |
+ theta = 0; |
+ } else { |
+ r = __Pyx_c_abs%(m)s(a); |
+ theta = atan2%(m)s(a.imag, a.real); |
+ } |
+ lnr = log%(m)s(r); |
+ z_r = exp%(m)s(lnr * b.real - theta * b.imag); |
+ z_theta = theta * b.real + lnr * b.imag; |
+ z.real = z_r * cos%(m)s(z_theta); |
+ z.imag = z_r * sin%(m)s(z_theta); |
+ return z; |
+ } |
+ #endif |
+#endif |
+""") |
+ |
+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 |
+ else: |
+ if base_type.same_as(c_py_unicode_type): |
+ self.is_pyunicode_ptr = 1 |
+ |
+ if self.is_string and not base_type.is_error: |
+ if base_type.signed: |
+ self.to_py_function = "__Pyx_PyObject_FromString" |
+ if self.is_ptr: |
+ if base_type.signed == 2: |
+ self.from_py_function = "__Pyx_PyObject_AsSString" |
+ else: |
+ self.from_py_function = "__Pyx_PyObject_AsString" |
+ else: |
+ self.to_py_function = "__Pyx_PyObject_FromUString" |
+ if self.is_ptr: |
+ self.from_py_function = "__Pyx_PyObject_AsUString" |
+ self.exception_value = "NULL" |
+ elif self.is_pyunicode_ptr and not base_type.is_error: |
+ self.to_py_function = "__Pyx_PyUnicode_FromUnicode" |
+ if self.is_ptr: |
+ self.from_py_function = "__Pyx_PyUnicode_AsUnicode" |
+ self.exception_value = "NULL" |
+ |
+ def py_type_name(self): |
+ if self.is_string: |
+ return "bytes" |
+ elif self.is_pyunicode_ptr: |
+ return "unicode" |
+ 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 |
+ |
+ def __init__(self, base_type, size): |
+ super(CArrayType, self).__init__(base_type) |
+ self.size = size |
+ |
+ def __eq__(self, other): |
+ if isinstance(other, CType) and other.is_array and self.size == other.size: |
+ return self.base_type.same_as(other.base_type) |
+ return False |
+ |
+ def __hash__(self): |
+ return hash(self.base_type) + 28 # arbitrarily chosen offset |
+ |
+ def __repr__(self): |
+ return "<CArrayType %s %s>" % (self.size, repr(self.base_type)) |
+ |
+ def same_as_resolved_type(self, other_type): |
+ return ((other_type.is_array and |
+ self.base_type.same_as(other_type.base_type)) |
+ or other_type is error_type) |
+ |
+ def assignable_from_resolved_type(self, src_type): |
+ # Can't assign to a variable of an array type |
+ return 0 |
+ |
+ def element_ptr_type(self): |
+ return c_ptr_type(self.base_type) |
+ |
+ def declaration_code(self, entity_code, |
+ for_display = 0, dll_linkage = None, pyrex = 0): |
+ if self.size is not None: |
+ dimension_code = self.size |
+ else: |
+ dimension_code = "" |
+ if entity_code.startswith("*"): |
+ entity_code = "(%s)" % entity_code |
+ return self.base_type.declaration_code( |
+ "%s[%s]" % (entity_code, dimension_code), |
+ for_display, dll_linkage, pyrex) |
+ |
+ def as_argument_type(self): |
+ return c_ptr_type(self.base_type) |
+ |
+ def is_complete(self): |
+ return self.size is not None |
+ |
+ def specialize(self, values): |
+ base_type = self.base_type.specialize(values) |
+ if base_type == self.base_type: |
+ return self |
+ else: |
+ return CArrayType(base_type) |
+ |
+ def deduce_template_params(self, actual): |
+ if isinstance(actual, CArrayType): |
+ return self.base_type.deduce_template_params(actual.base_type) |
+ else: |
+ return None |
+ |
+ |
+class CPtrType(CPointerBaseType): |
+ # base_type CType Reference type |
+ |
+ is_ptr = 1 |
+ default_value = "0" |
+ |
+ def __hash__(self): |
+ return hash(self.base_type) + 27 # arbitrarily chosen offset |
+ |
+ def __eq__(self, other): |
+ if isinstance(other, CType) and other.is_ptr: |
+ return self.base_type.same_as(other.base_type) |
+ return False |
+ |
+ def __ne__(self, other): |
+ return not (self == other) |
+ |
+ def __repr__(self): |
+ return "<CPtrType %s>" % repr(self.base_type) |
+ |
+ def same_as_resolved_type(self, other_type): |
+ return ((other_type.is_ptr and |
+ self.base_type.same_as(other_type.base_type)) |
+ or other_type is error_type) |
+ |
+ def declaration_code(self, entity_code, |
+ for_display = 0, dll_linkage = None, pyrex = 0): |
+ #print "CPtrType.declaration_code: pointer to", self.base_type ### |
+ return self.base_type.declaration_code( |
+ "*%s" % entity_code, |
+ for_display, dll_linkage, pyrex) |
+ |
+ def assignable_from_resolved_type(self, other_type): |
+ if other_type is error_type: |
+ return 1 |
+ if other_type.is_null_ptr: |
+ return 1 |
+ if self.base_type.is_const: |
+ self = CPtrType(self.base_type.const_base_type) |
+ if self.base_type.is_cfunction: |
+ if other_type.is_ptr: |
+ other_type = other_type.base_type.resolve() |
+ if other_type.is_cfunction: |
+ return self.base_type.pointer_assignable_from_resolved_type(other_type) |
+ else: |
+ return 0 |
+ if (self.base_type.is_cpp_class and other_type.is_ptr |
+ and other_type.base_type.is_cpp_class and other_type.base_type.is_subclass(self.base_type)): |
+ return 1 |
+ if other_type.is_array or other_type.is_ptr: |
+ return self.base_type.is_void or self.base_type.same_as(other_type.base_type) |
+ return 0 |
+ |
+ def specialize(self, values): |
+ base_type = self.base_type.specialize(values) |
+ if base_type == self.base_type: |
+ return self |
+ else: |
+ return CPtrType(base_type) |
+ |
+ def deduce_template_params(self, actual): |
+ if isinstance(actual, CPtrType): |
+ return self.base_type.deduce_template_params(actual.base_type) |
+ else: |
+ return None |
+ |
+ def invalid_value(self): |
+ return "1" |
+ |
+ def find_cpp_operation_type(self, operator, operand_type=None): |
+ if self.base_type.is_cpp_class: |
+ return self.base_type.find_cpp_operation_type(operator, operand_type) |
+ return None |
+ |
+class CNullPtrType(CPtrType): |
+ |
+ is_null_ptr = 1 |
+ |
+ |
+class CReferenceType(BaseType): |
+ |
+ is_reference = 1 |
+ |
+ def __init__(self, base_type): |
+ self.ref_base_type = base_type |
+ |
+ def __repr__(self): |
+ return "<CReferenceType %s>" % repr(self.ref_base_type) |
+ |
+ def __str__(self): |
+ return "%s &" % self.ref_base_type |
+ |
+ def declaration_code(self, entity_code, |
+ for_display = 0, dll_linkage = None, pyrex = 0): |
+ #print "CReferenceType.declaration_code: pointer to", self.base_type ### |
+ return self.ref_base_type.declaration_code( |
+ "&%s" % entity_code, |
+ for_display, dll_linkage, pyrex) |
+ |
+ def specialize(self, values): |
+ base_type = self.ref_base_type.specialize(values) |
+ if base_type == self.ref_base_type: |
+ return self |
+ else: |
+ return CReferenceType(base_type) |
+ |
+ def deduce_template_params(self, actual): |
+ return self.ref_base_type.deduce_template_params(actual) |
+ |
+ def __getattr__(self, name): |
+ return getattr(self.ref_base_type, name) |
+ |
+ |
+class CFuncType(CType): |
+ # return_type CType |
+ # args [CFuncTypeArg] |
+ # has_varargs boolean |
+ # exception_value string |
+ # exception_check boolean True if PyErr_Occurred check needed |
+ # calling_convention string Function calling convention |
+ # nogil boolean Can be called without gil |
+ # with_gil boolean Acquire gil around function body |
+ # templates [string] or None |
+ # cached_specialized_types [CFuncType] cached specialized versions of the CFuncType if defined in a pxd |
+ # from_fused boolean Indicates whether this is a specialized |
+ # C function |
+ # is_strict_signature boolean function refuses to accept coerced arguments |
+ # (used for optimisation overrides) |
+ # is_const_method boolean |
+ |
+ is_cfunction = 1 |
+ original_sig = None |
+ cached_specialized_types = None |
+ from_fused = False |
+ is_const_method = False |
+ |
+ subtypes = ['return_type', 'args'] |
+ |
+ def __init__(self, return_type, args, has_varargs = 0, |
+ exception_value = None, exception_check = 0, calling_convention = "", |
+ nogil = 0, with_gil = 0, is_overridable = 0, optional_arg_count = 0, |
+ is_const_method = False, templates = None, is_strict_signature = False): |
+ self.return_type = return_type |
+ self.args = args |
+ self.has_varargs = has_varargs |
+ self.optional_arg_count = optional_arg_count |
+ self.exception_value = exception_value |
+ self.exception_check = exception_check |
+ self.calling_convention = calling_convention |
+ self.nogil = nogil |
+ self.with_gil = with_gil |
+ self.is_overridable = is_overridable |
+ self.is_const_method = is_const_method |
+ self.templates = templates |
+ self.is_strict_signature = is_strict_signature |
+ |
+ def __repr__(self): |
+ arg_reprs = map(repr, self.args) |
+ if self.has_varargs: |
+ arg_reprs.append("...") |
+ if self.exception_value: |
+ except_clause = " %r" % self.exception_value |
+ else: |
+ except_clause = "" |
+ if self.exception_check: |
+ except_clause += "?" |
+ return "<CFuncType %s %s[%s]%s>" % ( |
+ repr(self.return_type), |
+ self.calling_convention_prefix(), |
+ ",".join(arg_reprs), |
+ except_clause) |
+ |
+ def calling_convention_prefix(self): |
+ cc = self.calling_convention |
+ if cc: |
+ return cc + " " |
+ else: |
+ return "" |
+ |
+ def as_argument_type(self): |
+ return c_ptr_type(self) |
+ |
+ def same_c_signature_as(self, other_type, as_cmethod = 0): |
+ return self.same_c_signature_as_resolved_type( |
+ other_type.resolve(), as_cmethod) |
+ |
+ def same_c_signature_as_resolved_type(self, other_type, as_cmethod = 0): |
+ #print "CFuncType.same_c_signature_as_resolved_type:", \ |
+ # self, other_type, "as_cmethod =", as_cmethod ### |
+ if other_type is error_type: |
+ return 1 |
+ if not other_type.is_cfunction: |
+ return 0 |
+ if self.is_overridable != other_type.is_overridable: |
+ return 0 |
+ nargs = len(self.args) |
+ if nargs != len(other_type.args): |
+ return 0 |
+ # When comparing C method signatures, the first argument |
+ # is exempt from compatibility checking (the proper check |
+ # is performed elsewhere). |
+ for i in range(as_cmethod, nargs): |
+ if not self.args[i].type.same_as( |
+ other_type.args[i].type): |
+ return 0 |
+ if self.has_varargs != other_type.has_varargs: |
+ return 0 |
+ if self.optional_arg_count != other_type.optional_arg_count: |
+ return 0 |
+ if not self.return_type.same_as(other_type.return_type): |
+ return 0 |
+ if not self.same_calling_convention_as(other_type): |
+ return 0 |
+ return 1 |
+ |
+ def compatible_signature_with(self, other_type, as_cmethod = 0): |
+ return self.compatible_signature_with_resolved_type(other_type.resolve(), as_cmethod) |
+ |
+ def compatible_signature_with_resolved_type(self, other_type, as_cmethod): |
+ #print "CFuncType.same_c_signature_as_resolved_type:", \ |
+ # self, other_type, "as_cmethod =", as_cmethod ### |
+ if other_type is error_type: |
+ return 1 |
+ if not other_type.is_cfunction: |
+ return 0 |
+ if not self.is_overridable and other_type.is_overridable: |
+ return 0 |
+ nargs = len(self.args) |
+ if nargs - self.optional_arg_count != len(other_type.args) - other_type.optional_arg_count: |
+ return 0 |
+ if self.optional_arg_count < other_type.optional_arg_count: |
+ return 0 |
+ # When comparing C method signatures, the first argument |
+ # is exempt from compatibility checking (the proper check |
+ # is performed elsewhere). |
+ for i in range(as_cmethod, len(other_type.args)): |
+ if not self.args[i].type.same_as( |
+ other_type.args[i].type): |
+ return 0 |
+ if self.has_varargs != other_type.has_varargs: |
+ return 0 |
+ if not self.return_type.subtype_of_resolved_type(other_type.return_type): |
+ return 0 |
+ if not self.same_calling_convention_as(other_type): |
+ return 0 |
+ if self.nogil != other_type.nogil: |
+ return 0 |
+ self.original_sig = other_type.original_sig or other_type |
+ return 1 |
+ |
+ |
+ def narrower_c_signature_than(self, other_type, as_cmethod = 0): |
+ return self.narrower_c_signature_than_resolved_type(other_type.resolve(), as_cmethod) |
+ |
+ def narrower_c_signature_than_resolved_type(self, other_type, as_cmethod): |
+ if other_type is error_type: |
+ return 1 |
+ if not other_type.is_cfunction: |
+ return 0 |
+ nargs = len(self.args) |
+ if nargs != len(other_type.args): |
+ return 0 |
+ for i in range(as_cmethod, nargs): |
+ if not self.args[i].type.subtype_of_resolved_type(other_type.args[i].type): |
+ return 0 |
+ else: |
+ self.args[i].needs_type_test = other_type.args[i].needs_type_test \ |
+ or not self.args[i].type.same_as(other_type.args[i].type) |
+ if self.has_varargs != other_type.has_varargs: |
+ return 0 |
+ if self.optional_arg_count != other_type.optional_arg_count: |
+ return 0 |
+ if not self.return_type.subtype_of_resolved_type(other_type.return_type): |
+ return 0 |
+ return 1 |
+ |
+ def same_calling_convention_as(self, other): |
+ ## XXX Under discussion ... |
+ ## callspec_words = ("__stdcall", "__cdecl", "__fastcall") |
+ ## cs1 = self.calling_convention |
+ ## cs2 = other.calling_convention |
+ ## if (cs1 in callspec_words or |
+ ## cs2 in callspec_words): |
+ ## return cs1 == cs2 |
+ ## else: |
+ ## return True |
+ sc1 = self.calling_convention == '__stdcall' |
+ sc2 = other.calling_convention == '__stdcall' |
+ return sc1 == sc2 |
+ |
+ def same_exception_signature_as(self, other_type): |
+ return self.same_exception_signature_as_resolved_type( |
+ other_type.resolve()) |
+ |
+ def same_exception_signature_as_resolved_type(self, other_type): |
+ return self.exception_value == other_type.exception_value \ |
+ and self.exception_check == other_type.exception_check |
+ |
+ def same_as_resolved_type(self, other_type, as_cmethod = 0): |
+ return self.same_c_signature_as_resolved_type(other_type, as_cmethod) \ |
+ and self.same_exception_signature_as_resolved_type(other_type) \ |
+ and self.nogil == other_type.nogil |
+ |
+ def pointer_assignable_from_resolved_type(self, other_type): |
+ return self.same_c_signature_as_resolved_type(other_type) \ |
+ and self.same_exception_signature_as_resolved_type(other_type) \ |
+ and not (self.nogil and not other_type.nogil) |
+ |
+ def declaration_code(self, entity_code, |
+ for_display = 0, dll_linkage = None, pyrex = 0, |
+ with_calling_convention = 1): |
+ arg_decl_list = [] |
+ for arg in self.args[:len(self.args)-self.optional_arg_count]: |
+ arg_decl_list.append( |
+ arg.type.declaration_code("", for_display, pyrex = pyrex)) |
+ if self.is_overridable: |
+ arg_decl_list.append("int %s" % Naming.skip_dispatch_cname) |
+ if self.optional_arg_count: |
+ arg_decl_list.append(self.op_arg_struct.declaration_code(Naming.optional_args_cname)) |
+ if self.has_varargs: |
+ arg_decl_list.append("...") |
+ arg_decl_code = ", ".join(arg_decl_list) |
+ if not arg_decl_code and not pyrex: |
+ arg_decl_code = "void" |
+ trailer = "" |
+ if (pyrex or for_display) and not self.return_type.is_pyobject: |
+ if self.exception_value and self.exception_check: |
+ trailer = " except? %s" % self.exception_value |
+ elif self.exception_value: |
+ trailer = " except %s" % self.exception_value |
+ elif self.exception_check == '+': |
+ trailer = " except +" |
+ else: |
+ " except *" # ignored |
+ if self.nogil: |
+ trailer += " nogil" |
+ if not with_calling_convention: |
+ cc = '' |
+ else: |
+ cc = self.calling_convention_prefix() |
+ if (not entity_code and cc) or entity_code.startswith("*"): |
+ entity_code = "(%s%s)" % (cc, entity_code) |
+ cc = "" |
+ if self.is_const_method: |
+ trailer += " const" |
+ return self.return_type.declaration_code( |
+ "%s%s(%s)%s" % (cc, entity_code, arg_decl_code, trailer), |
+ for_display, dll_linkage, pyrex) |
+ |
+ def function_header_code(self, func_name, arg_code): |
+ if self.is_const_method: |
+ trailer = " const" |
+ else: |
+ trailer = "" |
+ return "%s%s(%s)%s" % (self.calling_convention_prefix(), |
+ func_name, arg_code, trailer) |
+ |
+ def signature_string(self): |
+ s = self.declaration_code("") |
+ return s |
+ |
+ def signature_cast_string(self): |
+ s = self.declaration_code("(*)", with_calling_convention=False) |
+ return '(%s)' % s |
+ |
+ def specialize(self, values): |
+ result = CFuncType(self.return_type.specialize(values), |
+ [arg.specialize(values) for arg in self.args], |
+ has_varargs = self.has_varargs, |
+ exception_value = self.exception_value, |
+ exception_check = self.exception_check, |
+ calling_convention = self.calling_convention, |
+ nogil = self.nogil, |
+ with_gil = self.with_gil, |
+ is_overridable = self.is_overridable, |
+ optional_arg_count = self.optional_arg_count, |
+ is_const_method = self.is_const_method, |
+ templates = self.templates) |
+ |
+ result.from_fused = self.is_fused |
+ return result |
+ |
+ def opt_arg_cname(self, arg_name): |
+ return self.op_arg_struct.base_type.scope.lookup(arg_name).cname |
+ |
+ # Methods that deal with Fused Types |
+ # All but map_with_specific_entries should be called only on functions |
+ # with fused types (and not on their corresponding specific versions). |
+ |
+ def get_all_specialized_permutations(self, fused_types=None): |
+ """ |
+ Permute all the types. For every specific instance of a fused type, we |
+ want all other specific instances of all other fused types. |
+ |
+ It returns an iterable of two-tuples of the cname that should prefix |
+ the cname of the function, and a dict mapping any fused types to their |
+ respective specific types. |
+ """ |
+ assert self.is_fused |
+ |
+ if fused_types is None: |
+ fused_types = self.get_fused_types() |
+ |
+ return get_all_specialized_permutations(fused_types) |
+ |
+ def get_all_specialized_function_types(self): |
+ """ |
+ Get all the specific function types of this one. |
+ """ |
+ assert self.is_fused |
+ |
+ if self.entry.fused_cfunction: |
+ return [n.type for n in self.entry.fused_cfunction.nodes] |
+ elif self.cached_specialized_types is not None: |
+ return self.cached_specialized_types |
+ |
+ cfunc_entries = self.entry.scope.cfunc_entries |
+ cfunc_entries.remove(self.entry) |
+ |
+ result = [] |
+ permutations = self.get_all_specialized_permutations() |
+ |
+ for cname, fused_to_specific in permutations: |
+ new_func_type = self.entry.type.specialize(fused_to_specific) |
+ |
+ if self.optional_arg_count: |
+ # Remember, this method is set by CFuncDeclaratorNode |
+ self.declare_opt_arg_struct(new_func_type, cname) |
+ |
+ new_entry = copy.deepcopy(self.entry) |
+ new_func_type.specialize_entry(new_entry, cname) |
+ |
+ new_entry.type = new_func_type |
+ new_func_type.entry = new_entry |
+ result.append(new_func_type) |
+ |
+ cfunc_entries.append(new_entry) |
+ |
+ self.cached_specialized_types = result |
+ |
+ return result |
+ |
+ def get_fused_types(self, result=None, seen=None, subtypes=None): |
+ """Return fused types in the order they appear as parameter types""" |
+ return super(CFuncType, self).get_fused_types(result, seen, |
+ subtypes=['args']) |
+ |
+ def specialize_entry(self, entry, cname): |
+ assert not self.is_fused |
+ specialize_entry(entry, cname) |
+ |
+ |
+def specialize_entry(entry, cname): |
+ """ |
+ Specialize an entry of a copied fused function or method |
+ """ |
+ entry.is_fused_specialized = True |
+ entry.name = get_fused_cname(cname, entry.name) |
+ |
+ if entry.is_cmethod: |
+ entry.cname = entry.name |
+ if entry.is_inherited: |
+ entry.cname = StringEncoding.EncodedString( |
+ "%s.%s" % (Naming.obj_base_cname, entry.cname)) |
+ else: |
+ entry.cname = get_fused_cname(cname, entry.cname) |
+ |
+ if entry.func_cname: |
+ entry.func_cname = get_fused_cname(cname, entry.func_cname) |
+ |
+def get_fused_cname(fused_cname, orig_cname): |
+ """ |
+ Given the fused cname id and an original cname, return a specialized cname |
+ """ |
+ assert fused_cname and orig_cname |
+ return StringEncoding.EncodedString('%s%s%s' % (Naming.fused_func_prefix, |
+ fused_cname, orig_cname)) |
+ |
+def unique(somelist): |
+ seen = set() |
+ result = [] |
+ for obj in somelist: |
+ if obj not in seen: |
+ result.append(obj) |
+ seen.add(obj) |
+ |
+ return result |
+ |
+def get_all_specialized_permutations(fused_types): |
+ return _get_all_specialized_permutations(unique(fused_types)) |
+ |
+def _get_all_specialized_permutations(fused_types, id="", f2s=()): |
+ fused_type, = fused_types[0].get_fused_types() |
+ result = [] |
+ |
+ for newid, specific_type in enumerate(fused_type.types): |
+ # f2s = dict(f2s, **{ fused_type: specific_type }) |
+ f2s = dict(f2s) |
+ f2s.update({ fused_type: specific_type }) |
+ |
+ if id: |
+ cname = '%s_%s' % (id, newid) |
+ else: |
+ cname = str(newid) |
+ |
+ if len(fused_types) > 1: |
+ result.extend(_get_all_specialized_permutations( |
+ fused_types[1:], cname, f2s)) |
+ else: |
+ result.append((cname, f2s)) |
+ |
+ return result |
+ |
+def specialization_signature_string(fused_compound_type, fused_to_specific): |
+ """ |
+ Return the signature for a specialization of a fused type. e.g. |
+ |
+ floating[:] -> |
+ 'float' or 'double' |
+ |
+ cdef fused ft: |
+ float[:] |
+ double[:] |
+ |
+ ft -> |
+ 'float[:]' or 'double[:]' |
+ |
+ integral func(floating) -> |
+ 'int (*func)(float)' or ... |
+ """ |
+ fused_types = fused_compound_type.get_fused_types() |
+ if len(fused_types) == 1: |
+ fused_type = fused_types[0] |
+ else: |
+ fused_type = fused_compound_type |
+ |
+ return fused_type.specialize(fused_to_specific).typeof_name() |
+ |
+def get_specialized_types(type): |
+ """ |
+ Return a list of specialized types sorted in reverse order in accordance |
+ with their preference in runtime fused-type dispatch |
+ """ |
+ assert type.is_fused |
+ |
+ if isinstance(type, FusedType): |
+ result = type.types |
+ for specialized_type in result: |
+ specialized_type.specialization_string = specialized_type.typeof_name() |
+ else: |
+ result = [] |
+ for cname, f2s in get_all_specialized_permutations(type.get_fused_types()): |
+ specialized_type = type.specialize(f2s) |
+ specialized_type.specialization_string = ( |
+ specialization_signature_string(type, f2s)) |
+ result.append(specialized_type) |
+ |
+ return sorted(result) |
+ |
+ |
+class CFuncTypeArg(BaseType): |
+ # name string |
+ # cname string |
+ # type PyrexType |
+ # pos source file position |
+ |
+ # FIXME: is this the right setup? should None be allowed here? |
+ not_none = False |
+ or_none = False |
+ accept_none = True |
+ accept_builtin_subtypes = False |
+ |
+ subtypes = ['type'] |
+ |
+ def __init__(self, name, type, pos, cname=None): |
+ self.name = name |
+ if cname is not None: |
+ self.cname = cname |
+ else: |
+ self.cname = Naming.var_prefix + name |
+ self.type = type |
+ self.pos = pos |
+ self.needs_type_test = False # TODO: should these defaults be set in analyse_types()? |
+ |
+ def __repr__(self): |
+ return "%s:%s" % (self.name, repr(self.type)) |
+ |
+ def declaration_code(self, for_display = 0): |
+ return self.type.declaration_code(self.cname, for_display) |
+ |
+ def specialize(self, values): |
+ return CFuncTypeArg(self.name, self.type.specialize(values), self.pos, self.cname) |
+ |
+class ToPyStructUtilityCode(object): |
+ |
+ requires = None |
+ |
+ def __init__(self, type, forward_decl): |
+ self.type = type |
+ self.header = "static PyObject* %s(%s)" % (type.to_py_function, |
+ type.declaration_code('s')) |
+ self.forward_decl = forward_decl |
+ |
+ def __eq__(self, other): |
+ return isinstance(other, ToPyStructUtilityCode) and self.header == other.header |
+ |
+ def __hash__(self): |
+ return hash(self.header) |
+ |
+ def get_tree(self): |
+ pass |
+ |
+ def put_code(self, output): |
+ code = output['utility_code_def'] |
+ proto = output['utility_code_proto'] |
+ |
+ code.putln("%s {" % self.header) |
+ code.putln("PyObject* res;") |
+ code.putln("PyObject* member;") |
+ code.putln("res = PyDict_New(); if (res == NULL) return NULL;") |
+ for member in self.type.scope.var_entries: |
+ nameconst_cname = code.get_py_string_const(member.name, identifier=True) |
+ code.putln("member = %s(s.%s); if (member == NULL) goto bad;" % ( |
+ member.type.to_py_function, member.cname)) |
+ code.putln("if (PyDict_SetItem(res, %s, member) < 0) goto bad;" % nameconst_cname) |
+ code.putln("Py_DECREF(member);") |
+ code.putln("return res;") |
+ code.putln("bad:") |
+ code.putln("Py_XDECREF(member);") |
+ code.putln("Py_DECREF(res);") |
+ code.putln("return NULL;") |
+ code.putln("}") |
+ |
+ # This is a bit of a hack, we need a forward declaration |
+ # due to the way things are ordered in the module... |
+ if self.forward_decl: |
+ proto.putln(self.type.declaration_code('') + ';') |
+ proto.putln(self.header + ";") |
+ |
+ def inject_tree_and_scope_into(self, module_node): |
+ pass |
+ |
+ |
+class CStructOrUnionType(CType): |
+ # name string |
+ # cname string |
+ # kind string "struct" or "union" |
+ # scope StructOrUnionScope, or None if incomplete |
+ # typedef_flag boolean |
+ # packed boolean |
+ |
+ # entry Entry |
+ |
+ is_struct_or_union = 1 |
+ has_attributes = 1 |
+ exception_check = True |
+ |
+ def __init__(self, name, kind, scope, typedef_flag, cname, packed=False): |
+ self.name = name |
+ self.cname = cname |
+ self.kind = kind |
+ self.scope = scope |
+ self.typedef_flag = typedef_flag |
+ self.is_struct = kind == 'struct' |
+ if self.is_struct: |
+ self.to_py_function = "%s_to_py_%s" % (Naming.convert_func_prefix, self.cname) |
+ self.from_py_function = "%s_from_py_%s" % (Naming.convert_func_prefix, self.cname) |
+ self.exception_check = True |
+ self._convert_to_py_code = None |
+ self._convert_from_py_code = None |
+ self.packed = packed |
+ |
+ def create_to_py_utility_code(self, env): |
+ if env.outer_scope is None: |
+ return False |
+ |
+ if self._convert_to_py_code is False: |
+ return None # tri-state-ish |
+ |
+ if self._convert_to_py_code is None: |
+ for member in self.scope.var_entries: |
+ if not member.type.create_to_py_utility_code(env): |
+ self.to_py_function = None |
+ self._convert_to_py_code = False |
+ return False |
+ forward_decl = (self.entry.visibility != 'extern') |
+ self._convert_to_py_code = ToPyStructUtilityCode(self, forward_decl) |
+ |
+ env.use_utility_code(self._convert_to_py_code) |
+ return True |
+ |
+ def create_from_py_utility_code(self, env): |
+ if env.outer_scope is None: |
+ return False |
+ |
+ if self._convert_from_py_code is False: |
+ return None # tri-state-ish |
+ |
+ if self._convert_from_py_code is None: |
+ for member in self.scope.var_entries: |
+ if not member.type.create_from_py_utility_code(env): |
+ self.from_py_function = None |
+ self._convert_from_py_code = False |
+ return False |
+ |
+ context = dict( |
+ struct_type_decl=self.declaration_code(""), |
+ var_entries=self.scope.var_entries, |
+ funcname=self.from_py_function, |
+ ) |
+ self._convert_from_py_code = TempitaUtilityCode.load( |
+ "FromPyStructUtility", "TypeConversion.c", context=context) |
+ |
+ env.use_utility_code(self._convert_from_py_code) |
+ return True |
+ |
+ def __repr__(self): |
+ return "<CStructOrUnionType %s %s%s>" % ( |
+ self.name, self.cname, |
+ ("", " typedef")[self.typedef_flag]) |
+ |
+ def declaration_code(self, entity_code, |
+ for_display=0, dll_linkage=None, pyrex=0): |
+ if pyrex or for_display: |
+ base_code = self.name |
+ else: |
+ if self.typedef_flag: |
+ base_code = self.cname |
+ else: |
+ base_code = "%s %s" % (self.kind, self.cname) |
+ base_code = public_decl(base_code, dll_linkage) |
+ return self.base_declaration_code(base_code, entity_code) |
+ |
+ def __eq__(self, other): |
+ try: |
+ return (isinstance(other, CStructOrUnionType) and |
+ self.name == other.name) |
+ except AttributeError: |
+ return False |
+ |
+ def __lt__(self, other): |
+ try: |
+ return self.name < other.name |
+ except AttributeError: |
+ # this is arbitrary, but it makes sure we always have |
+ # *some* kind of order |
+ return False |
+ |
+ def __hash__(self): |
+ return hash(self.cname) ^ hash(self.kind) |
+ |
+ def is_complete(self): |
+ return self.scope is not None |
+ |
+ def attributes_known(self): |
+ return self.is_complete() |
+ |
+ def can_be_complex(self): |
+ # Does the struct consist of exactly two identical floats? |
+ fields = self.scope.var_entries |
+ if len(fields) != 2: return False |
+ a, b = fields |
+ return (a.type.is_float and b.type.is_float and |
+ a.type.declaration_code("") == |
+ b.type.declaration_code("")) |
+ |
+ def struct_nesting_depth(self): |
+ child_depths = [x.type.struct_nesting_depth() |
+ for x in self.scope.var_entries] |
+ return max(child_depths) + 1 |
+ |
+ def cast_code(self, expr_code): |
+ if self.is_struct: |
+ return expr_code |
+ return super(CStructOrUnionType, self).cast_code(expr_code) |
+ |
+ |
+builtin_cpp_conversions = ("std::string", |
+ "std::pair", |
+ "std::vector", "std::list", |
+ "std::set", "std::unordered_set", |
+ "std::map", "std::unordered_map") |
+ |
+class CppClassType(CType): |
+ # name string |
+ # cname string |
+ # scope CppClassScope |
+ # templates [string] or None |
+ |
+ is_cpp_class = 1 |
+ has_attributes = 1 |
+ exception_check = True |
+ namespace = None |
+ |
+ # For struct-like declaration. |
+ kind = "struct" |
+ packed = False |
+ typedef_flag = False |
+ |
+ subtypes = ['templates'] |
+ |
+ def __init__(self, name, scope, cname, base_classes, templates = None, template_type = None): |
+ self.name = name |
+ self.cname = cname |
+ self.scope = scope |
+ self.base_classes = base_classes |
+ self.operators = [] |
+ self.templates = templates |
+ self.template_type = template_type |
+ self.specializations = {} |
+ self.is_cpp_string = cname == 'std::string' |
+ |
+ def use_conversion_utility(self, from_or_to): |
+ pass |
+ |
+ def maybe_unordered(self): |
+ if 'unordered' in self.cname: |
+ return 'unordered_' |
+ else: |
+ return '' |
+ |
+ def create_from_py_utility_code(self, env): |
+ if self.from_py_function is not None: |
+ return True |
+ if self.cname in builtin_cpp_conversions: |
+ X = "XYZABC" |
+ tags = [] |
+ declarations = ["cdef extern from *:"] |
+ for ix, T in enumerate(self.templates or []): |
+ if T.is_pyobject or not T.create_from_py_utility_code(env): |
+ return False |
+ tags.append(T.specialization_name()) |
+ if T.exception_value is not None: |
+ except_clause = T.exception_value |
+ if T.exception_check: |
+ except_clause = "? %s" % except_clause |
+ declarations.append( |
+ " ctypedef %s %s '%s'" % ( |
+ T.declaration_code("", for_display=True), X[ix], T.declaration_code(""))) |
+ else: |
+ except_clause = "*" |
+ declarations.append( |
+ " ctypedef struct %s '%s':\n pass" % ( |
+ X[ix], T.declaration_code(""))) |
+ declarations.append( |
+ " cdef %s %s_from_py '%s' (object) except %s" % ( |
+ X[ix], X[ix], T.from_py_function, except_clause)) |
+ cls = self.cname[5:] |
+ cname = '__pyx_convert_%s_from_py_%s' % (cls, '____'.join(tags)) |
+ context = { |
+ 'template_type_declarations': '\n'.join(declarations), |
+ 'cname': cname, |
+ 'maybe_unordered': self.maybe_unordered(), |
+ } |
+ from UtilityCode import CythonUtilityCode |
+ env.use_utility_code(CythonUtilityCode.load(cls.replace('unordered_', '') + ".from_py", "CppConvert.pyx", context=context)) |
+ self.from_py_function = cname |
+ return True |
+ |
+ def create_to_py_utility_code(self, env): |
+ if self.to_py_function is not None: |
+ return True |
+ if self.cname in builtin_cpp_conversions: |
+ X = "XYZABC" |
+ tags = [] |
+ declarations = ["cdef extern from *:"] |
+ for ix, T in enumerate(self.templates or []): |
+ if not T.create_to_py_utility_code(env): |
+ return False |
+ tags.append(T.specialization_name()) |
+ declarations.append( |
+ " ctypedef struct %s '%s':\n pass" % ( |
+ X[ix], T.declaration_code(""))) |
+ declarations.append( |
+ " cdef object %s_to_py '%s' (%s)" % ( |
+ X[ix], T.to_py_function, X[ix])) |
+ cls = self.cname[5:] |
+ cname = "__pyx_convert_%s_to_py_%s" % (cls, "____".join(tags)) |
+ context = { |
+ 'template_type_declarations': '\n'.join(declarations), |
+ 'cname': cname, |
+ 'maybe_unordered': self.maybe_unordered(), |
+ } |
+ from UtilityCode import CythonUtilityCode |
+ env.use_utility_code(CythonUtilityCode.load(cls.replace('unordered_', '') + ".to_py", "CppConvert.pyx", context=context)) |
+ self.to_py_function = cname |
+ return True |
+ |
+ def specialize_here(self, pos, template_values = None): |
+ if self.templates is None: |
+ error(pos, "'%s' type is not a template" % self) |
+ return error_type |
+ if len(self.templates) != len(template_values): |
+ error(pos, "%s templated type receives %d arguments, got %d" % |
+ (self.name, len(self.templates), len(template_values))) |
+ return error_type |
+ has_object_template_param = False |
+ for value in template_values: |
+ if value.is_pyobject: |
+ has_object_template_param = True |
+ error(pos, |
+ "Python object type '%s' cannot be used as a template argument" % value) |
+ if has_object_template_param: |
+ return error_type |
+ return self.specialize(dict(zip(self.templates, template_values))) |
+ |
+ def specialize(self, values): |
+ if not self.templates and not self.namespace: |
+ return self |
+ if self.templates is None: |
+ self.templates = [] |
+ key = tuple(values.items()) |
+ if key in self.specializations: |
+ return self.specializations[key] |
+ template_values = [t.specialize(values) for t in self.templates] |
+ specialized = self.specializations[key] = \ |
+ CppClassType(self.name, None, self.cname, [], template_values, template_type=self) |
+ # Need to do these *after* self.specializations[key] is set |
+ # to avoid infinite recursion on circular references. |
+ specialized.base_classes = [b.specialize(values) for b in self.base_classes] |
+ specialized.scope = self.scope.specialize(values) |
+ if self.namespace is not None: |
+ specialized.namespace = self.namespace.specialize(values) |
+ return specialized |
+ |
+ def deduce_template_params(self, actual): |
+ if self == actual: |
+ return {} |
+ # TODO(robertwb): Actual type equality. |
+ elif self.declaration_code("") == actual.template_type.declaration_code(""): |
+ return reduce( |
+ merge_template_deductions, |
+ [formal_param.deduce_template_params(actual_param) for (formal_param, actual_param) in zip(self.templates, actual.templates)], |
+ {}) |
+ else: |
+ return None |
+ |
+ def declaration_code(self, entity_code, |
+ for_display = 0, dll_linkage = None, pyrex = 0): |
+ if self.templates: |
+ template_strings = [param.declaration_code('', for_display, None, pyrex) |
+ for param in self.templates] |
+ if for_display: |
+ brackets = "[%s]" |
+ else: |
+ brackets = "<%s>" |
+ templates = brackets % ",".join(template_strings) |
+ if templates[-2:] == ">>": |
+ templates = templates[:-2] + "> >" |
+ else: |
+ templates = "" |
+ if pyrex or for_display: |
+ base_code = "%s%s" % (self.name, templates) |
+ else: |
+ base_code = "%s%s" % (self.cname, templates) |
+ if self.namespace is not None: |
+ base_code = "%s::%s" % (self.namespace.declaration_code(''), base_code) |
+ base_code = public_decl(base_code, dll_linkage) |
+ return self.base_declaration_code(base_code, entity_code) |
+ |
+ def is_subclass(self, other_type): |
+ if self.same_as_resolved_type(other_type): |
+ return 1 |
+ for base_class in self.base_classes: |
+ if base_class.is_subclass(other_type): |
+ return 1 |
+ return 0 |
+ |
+ def same_as_resolved_type(self, other_type): |
+ if other_type.is_cpp_class: |
+ if self == other_type: |
+ return 1 |
+ elif (self.cname == other_type.cname and |
+ self.template_type and other_type.template_type): |
+ if self.templates == other_type.templates: |
+ return 1 |
+ for t1, t2 in zip(self.templates, other_type.templates): |
+ if not t1.same_as_resolved_type(t2): |
+ return 0 |
+ return 1 |
+ return 0 |
+ |
+ def assignable_from_resolved_type(self, other_type): |
+ # TODO: handle operator=(...) here? |
+ if other_type is error_type: |
+ return True |
+ return other_type.is_cpp_class and other_type.is_subclass(self) |
+ |
+ def attributes_known(self): |
+ return self.scope is not None |
+ |
+ def find_cpp_operation_type(self, operator, operand_type=None): |
+ operands = [self] |
+ if operand_type is not None: |
+ operands.append(operand_type) |
+ # pos == None => no errors |
+ operator_entry = self.scope.lookup_operator_for_types(None, operator, operands) |
+ if not operator_entry: |
+ return None |
+ func_type = operator_entry.type |
+ if func_type.is_ptr: |
+ func_type = func_type.base_type |
+ return func_type.return_type |
+ |
+ def check_nullary_constructor(self, pos, msg="stack allocated"): |
+ constructor = self.scope.lookup(u'<init>') |
+ if constructor is not None and best_match([], constructor.all_alternatives()) is None: |
+ error(pos, "C++ class must have a nullary constructor to be %s" % msg) |
+ |
+ |
+class TemplatePlaceholderType(CType): |
+ |
+ def __init__(self, name): |
+ self.name = name |
+ |
+ def declaration_code(self, entity_code, |
+ for_display = 0, dll_linkage = None, pyrex = 0): |
+ if entity_code: |
+ return self.name + " " + entity_code |
+ else: |
+ return self.name |
+ |
+ def specialize(self, values): |
+ if self in values: |
+ return values[self] |
+ else: |
+ return self |
+ |
+ def deduce_template_params(self, actual): |
+ return {self: actual} |
+ |
+ def same_as_resolved_type(self, other_type): |
+ if isinstance(other_type, TemplatePlaceholderType): |
+ return self.name == other_type.name |
+ else: |
+ return 0 |
+ |
+ def __hash__(self): |
+ return hash(self.name) |
+ |
+ def __cmp__(self, other): |
+ if isinstance(other, TemplatePlaceholderType): |
+ return cmp(self.name, other.name) |
+ else: |
+ return cmp(type(self), type(other)) |
+ |
+ def __eq__(self, other): |
+ if isinstance(other, TemplatePlaceholderType): |
+ return self.name == other.name |
+ else: |
+ return False |
+ |
+class CEnumType(CType): |
+ # name string |
+ # cname string or None |
+ # typedef_flag boolean |
+ |
+ is_enum = 1 |
+ signed = 1 |
+ rank = -1 # Ranks below any integer type |
+ to_py_function = "PyInt_FromLong" |
+ from_py_function = "PyInt_AsLong" |
+ |
+ def __init__(self, name, cname, typedef_flag): |
+ self.name = name |
+ self.cname = cname |
+ self.values = [] |
+ self.typedef_flag = typedef_flag |
+ |
+ def __str__(self): |
+ return self.name |
+ |
+ def __repr__(self): |
+ return "<CEnumType %s %s%s>" % (self.name, self.cname, |
+ ("", " typedef")[self.typedef_flag]) |
+ |
+ def declaration_code(self, entity_code, |
+ for_display = 0, dll_linkage = None, pyrex = 0): |
+ if pyrex or for_display: |
+ base_code = self.name |
+ else: |
+ if self.typedef_flag: |
+ base_code = self.cname |
+ else: |
+ base_code = "enum %s" % self.cname |
+ base_code = public_decl(base_code, dll_linkage) |
+ return self.base_declaration_code(base_code, entity_code) |
+ |
+class UnspecifiedType(PyrexType): |
+ # Used as a placeholder until the type can be determined. |
+ |
+ is_unspecified = 1 |
+ |
+ def declaration_code(self, entity_code, |
+ for_display = 0, dll_linkage = None, pyrex = 0): |
+ return "<unspecified>" |
+ |
+ def same_as_resolved_type(self, other_type): |
+ return False |
+ |
+ |
+class ErrorType(PyrexType): |
+ # Used to prevent propagation of error messages. |
+ |
+ is_error = 1 |
+ exception_value = "0" |
+ exception_check = 0 |
+ to_py_function = "dummy" |
+ from_py_function = "dummy" |
+ |
+ def create_to_py_utility_code(self, env): |
+ return True |
+ |
+ def create_from_py_utility_code(self, env): |
+ return True |
+ |
+ def declaration_code(self, entity_code, |
+ for_display = 0, dll_linkage = None, pyrex = 0): |
+ return "<error>" |
+ |
+ def same_as_resolved_type(self, other_type): |
+ return 1 |
+ |
+ def error_condition(self, result_code): |
+ return "dummy" |
+ |
+ |
+rank_to_type_name = ( |
+ "char", # 0 |
+ "short", # 1 |
+ "int", # 2 |
+ "long", # 3 |
+ "PY_LONG_LONG", # 4 |
+ "float", # 5 |
+ "double", # 6 |
+ "long double", # 7 |
+) |
+ |
+_rank_to_type_name = list(rank_to_type_name) |
+RANK_INT = _rank_to_type_name.index('int') |
+RANK_LONG = _rank_to_type_name.index('long') |
+RANK_FLOAT = _rank_to_type_name.index('float') |
+UNSIGNED = 0 |
+SIGNED = 2 |
+ |
+error_type = ErrorType() |
+unspecified_type = UnspecifiedType() |
+ |
+py_object_type = PyObjectType() |
+ |
+c_void_type = CVoidType() |
+ |
+c_uchar_type = CIntType(0, UNSIGNED) |
+c_ushort_type = CIntType(1, UNSIGNED) |
+c_uint_type = CIntType(2, UNSIGNED) |
+c_ulong_type = CIntType(3, UNSIGNED) |
+c_ulonglong_type = CIntType(4, UNSIGNED) |
+ |
+c_char_type = CIntType(0) |
+c_short_type = CIntType(1) |
+c_int_type = CIntType(2) |
+c_long_type = CIntType(3) |
+c_longlong_type = CIntType(4) |
+ |
+c_schar_type = CIntType(0, SIGNED) |
+c_sshort_type = CIntType(1, SIGNED) |
+c_sint_type = CIntType(2, SIGNED) |
+c_slong_type = CIntType(3, SIGNED) |
+c_slonglong_type = CIntType(4, SIGNED) |
+ |
+c_float_type = CFloatType(5, math_h_modifier='f') |
+c_double_type = CFloatType(6) |
+c_longdouble_type = CFloatType(7, math_h_modifier='l') |
+ |
+c_float_complex_type = CComplexType(c_float_type) |
+c_double_complex_type = CComplexType(c_double_type) |
+c_longdouble_complex_type = CComplexType(c_longdouble_type) |
+ |
+c_anon_enum_type = CAnonEnumType(-1) |
+c_returncode_type = CReturnCodeType(RANK_INT) |
+c_bint_type = CBIntType(RANK_INT) |
+c_py_unicode_type = CPyUnicodeIntType(RANK_INT-0.5, UNSIGNED) |
+c_py_ucs4_type = CPyUCS4IntType(RANK_LONG-0.5, UNSIGNED) |
+c_py_hash_t_type = CPyHashTType(RANK_LONG+0.5, SIGNED) |
+c_py_ssize_t_type = CPySSizeTType(RANK_LONG+0.5, SIGNED) |
+c_ssize_t_type = CSSizeTType(RANK_LONG+0.5, SIGNED) |
+c_size_t_type = CSizeTType(RANK_LONG+0.5, UNSIGNED) |
+c_ptrdiff_t_type = CPtrdiffTType(RANK_LONG+0.75, SIGNED) |
+ |
+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_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) |
+c_py_ssize_t_ptr_type = CPtrType(c_py_ssize_t_type) |
+c_ssize_t_ptr_type = CPtrType(c_ssize_t_type) |
+c_size_t_ptr_type = CPtrType(c_size_t_type) |
+ |
+# GIL state |
+c_gilstate_type = CEnumType("PyGILState_STATE", "PyGILState_STATE", True) |
+c_threadstate_type = CStructOrUnionType("PyThreadState", "struct", None, 1, "PyThreadState") |
+c_threadstate_ptr_type = CPtrType(c_threadstate_type) |
+ |
+# the Py_buffer type is defined in Builtin.py |
+c_py_buffer_type = CStructOrUnionType("Py_buffer", "struct", None, 1, "Py_buffer") |
+c_py_buffer_ptr_type = CPtrType(c_py_buffer_type) |
+ |
+# Not sure whether the unsigned versions and 'long long' should be in there |
+# long long requires C99 and might be slow, and would always get preferred |
+# when specialization happens through calling and not indexing |
+cy_integral_type = FusedType([c_short_type, c_int_type, c_long_type], |
+ name="integral") |
+# Omitting long double as it might be slow |
+cy_floating_type = FusedType([c_float_type, c_double_type], name="floating") |
+cy_numeric_type = FusedType([c_short_type, |
+ c_int_type, |
+ c_long_type, |
+ c_float_type, |
+ c_double_type, |
+ c_float_complex_type, |
+ c_double_complex_type], name="numeric") |
+ |
+# buffer-related structs |
+c_buf_diminfo_type = CStructOrUnionType("__Pyx_Buf_DimInfo", "struct", |
+ None, 1, "__Pyx_Buf_DimInfo") |
+c_pyx_buffer_type = CStructOrUnionType("__Pyx_Buffer", "struct", None, 1, "__Pyx_Buffer") |
+c_pyx_buffer_ptr_type = CPtrType(c_pyx_buffer_type) |
+c_pyx_buffer_nd_type = CStructOrUnionType("__Pyx_LocalBuf_ND", "struct", |
+ None, 1, "__Pyx_LocalBuf_ND") |
+ |
+cython_memoryview_type = CStructOrUnionType("__pyx_memoryview_obj", "struct", |
+ None, 0, "__pyx_memoryview_obj") |
+ |
+memoryviewslice_type = CStructOrUnionType("memoryviewslice", "struct", |
+ None, 1, "__Pyx_memviewslice") |
+ |
+modifiers_and_name_to_type = { |
+ #(signed, longness, name) : type |
+ (0, 0, "char"): c_uchar_type, |
+ (1, 0, "char"): c_char_type, |
+ (2, 0, "char"): c_schar_type, |
+ |
+ (0, -1, "int"): c_ushort_type, |
+ (0, 0, "int"): c_uint_type, |
+ (0, 1, "int"): c_ulong_type, |
+ (0, 2, "int"): c_ulonglong_type, |
+ |
+ (1, -1, "int"): c_short_type, |
+ (1, 0, "int"): c_int_type, |
+ (1, 1, "int"): c_long_type, |
+ (1, 2, "int"): c_longlong_type, |
+ |
+ (2, -1, "int"): c_sshort_type, |
+ (2, 0, "int"): c_sint_type, |
+ (2, 1, "int"): c_slong_type, |
+ (2, 2, "int"): c_slonglong_type, |
+ |
+ (1, 0, "float"): c_float_type, |
+ (1, 0, "double"): c_double_type, |
+ (1, 1, "double"): c_longdouble_type, |
+ |
+ (1, 0, "complex"): c_double_complex_type, # C: float, Python: double => Python wins |
+ (1, 0, "floatcomplex"): c_float_complex_type, |
+ (1, 0, "doublecomplex"): c_double_complex_type, |
+ (1, 1, "doublecomplex"): c_longdouble_complex_type, |
+ |
+ # |
+ (1, 0, "void"): c_void_type, |
+ |
+ (1, 0, "bint"): c_bint_type, |
+ (0, 0, "Py_UNICODE"): c_py_unicode_type, |
+ (0, 0, "Py_UCS4"): c_py_ucs4_type, |
+ (2, 0, "Py_hash_t"): c_py_hash_t_type, |
+ (2, 0, "Py_ssize_t"): c_py_ssize_t_type, |
+ (2, 0, "ssize_t") : c_ssize_t_type, |
+ (0, 0, "size_t") : c_size_t_type, |
+ (2, 0, "ptrdiff_t") : c_ptrdiff_t_type, |
+ |
+ (1, 0, "object"): py_object_type, |
+} |
+ |
+def is_promotion(src_type, dst_type): |
+ # It's hard to find a hard definition of promotion, but empirical |
+ # evidence suggests that the below is all that's allowed. |
+ if src_type.is_numeric: |
+ if dst_type.same_as(c_int_type): |
+ unsigned = (not src_type.signed) |
+ return (src_type.is_enum or |
+ (src_type.is_int and |
+ unsigned + src_type.rank < dst_type.rank)) |
+ elif dst_type.same_as(c_double_type): |
+ return src_type.is_float and src_type.rank <= dst_type.rank |
+ return False |
+ |
+def best_match(args, functions, pos=None, env=None): |
+ """ |
+ Given a list args of arguments and a list of functions, choose one |
+ to call which seems to be the "best" fit for this list of arguments. |
+ This function is used, e.g., when deciding which overloaded method |
+ to dispatch for C++ classes. |
+ |
+ We first eliminate functions based on arity, and if only one |
+ function has the correct arity, we return it. Otherwise, we weight |
+ functions based on how much work must be done to convert the |
+ arguments, with the following priorities: |
+ * identical types or pointers to identical types |
+ * promotions |
+ * non-Python types |
+ That is, we prefer functions where no arguments need converted, |
+ and failing that, functions where only promotions are required, and |
+ so on. |
+ |
+ If no function is deemed a good fit, or if two or more functions have |
+ the same weight, we return None (as there is no best match). If pos |
+ is not None, we also generate an error. |
+ """ |
+ # TODO: args should be a list of types, not a list of Nodes. |
+ actual_nargs = len(args) |
+ |
+ candidates = [] |
+ errors = [] |
+ for func in functions: |
+ error_mesg = "" |
+ func_type = func.type |
+ if func_type.is_ptr: |
+ func_type = func_type.base_type |
+ # Check function type |
+ if not func_type.is_cfunction: |
+ if not func_type.is_error and pos is not None: |
+ error_mesg = "Calling non-function type '%s'" % func_type |
+ errors.append((func, error_mesg)) |
+ continue |
+ # Check no. of args |
+ max_nargs = len(func_type.args) |
+ min_nargs = max_nargs - func_type.optional_arg_count |
+ if actual_nargs < min_nargs or \ |
+ (not func_type.has_varargs and actual_nargs > max_nargs): |
+ if max_nargs == min_nargs and not func_type.has_varargs: |
+ expectation = max_nargs |
+ elif actual_nargs < min_nargs: |
+ expectation = "at least %s" % min_nargs |
+ else: |
+ expectation = "at most %s" % max_nargs |
+ error_mesg = "Call with wrong number of arguments (expected %s, got %s)" \ |
+ % (expectation, actual_nargs) |
+ errors.append((func, error_mesg)) |
+ continue |
+ if func_type.templates: |
+ arg_types = [arg.type for arg in args] |
+ deductions = reduce( |
+ merge_template_deductions, |
+ [pattern.type.deduce_template_params(actual) for (pattern, actual) in zip(func_type.args, arg_types)], |
+ {}) |
+ if deductions is None: |
+ errors.append((func, "Unable to deduce type parameters")) |
+ elif len(deductions) < len(func_type.templates): |
+ errors.append((func, "Unable to deduce type parameter %s" % ( |
+ ", ".join([param.name for param in set(func_type.templates) - set(deductions.keys())])))) |
+ else: |
+ type_list = [deductions[param] for param in func_type.templates] |
+ from Symtab import Entry |
+ specialization = Entry( |
+ name = func.name + "[%s]" % ",".join([str(t) for t in type_list]), |
+ cname = func.cname + "<%s>" % ",".join([t.declaration_code("") for t in type_list]), |
+ type = func_type.specialize(deductions), |
+ pos = func.pos) |
+ candidates.append((specialization, specialization.type)) |
+ else: |
+ candidates.append((func, func_type)) |
+ |
+ # Optimize the most common case of no overloading... |
+ if len(candidates) == 1: |
+ return candidates[0][0] |
+ elif len(candidates) == 0: |
+ if pos is not None: |
+ func, errmsg = errors[0] |
+ if len(errors) == 1 or [1 for func, e in errors if e == errmsg]: |
+ error(pos, errmsg) |
+ else: |
+ error(pos, "no suitable method found") |
+ return None |
+ |
+ possibilities = [] |
+ bad_types = [] |
+ needed_coercions = {} |
+ |
+ for index, (func, func_type) in enumerate(candidates): |
+ score = [0,0,0,0] |
+ for i in range(min(len(args), len(func_type.args))): |
+ src_type = args[i].type |
+ dst_type = func_type.args[i].type |
+ |
+ assignable = dst_type.assignable_from(src_type) |
+ |
+ # Now take care of normal string literals. So when you call a cdef |
+ # function that takes a char *, the coercion will mean that the |
+ # type will simply become bytes. We need to do this coercion |
+ # manually for overloaded and fused functions |
+ if not assignable and src_type.is_pyobject: |
+ if (src_type.is_builtin_type and src_type.name == 'str' and |
+ dst_type.resolve() is c_char_ptr_type): |
+ c_src_type = c_char_ptr_type |
+ else: |
+ c_src_type = src_type.default_coerced_ctype() |
+ |
+ if c_src_type: |
+ assignable = dst_type.assignable_from(c_src_type) |
+ if assignable: |
+ src_type = c_src_type |
+ needed_coercions[func] = i, dst_type |
+ |
+ if assignable: |
+ if src_type == dst_type or dst_type.same_as(src_type): |
+ pass # score 0 |
+ elif func_type.is_strict_signature: |
+ break # exact match requested but not found |
+ elif is_promotion(src_type, dst_type): |
+ score[2] += 1 |
+ elif ((src_type.is_int and dst_type.is_int) or |
+ (src_type.is_float and dst_type.is_float)): |
+ score[2] += abs(dst_type.rank + (not dst_type.signed) - |
+ (src_type.rank + (not src_type.signed))) + 1 |
+ elif not src_type.is_pyobject: |
+ score[1] += 1 |
+ else: |
+ score[0] += 1 |
+ else: |
+ error_mesg = "Invalid conversion from '%s' to '%s'"%(src_type, |
+ dst_type) |
+ bad_types.append((func, error_mesg)) |
+ break |
+ else: |
+ possibilities.append((score, index, func)) # so we can sort it |
+ |
+ if possibilities: |
+ possibilities.sort() |
+ if len(possibilities) > 1: |
+ score1 = possibilities[0][0] |
+ score2 = possibilities[1][0] |
+ if score1 == score2: |
+ if pos is not None: |
+ error(pos, "ambiguous overloaded method") |
+ return None |
+ |
+ function = possibilities[0][-1] |
+ |
+ if function in needed_coercions and env: |
+ arg_i, coerce_to_type = needed_coercions[function] |
+ args[arg_i] = args[arg_i].coerce_to(coerce_to_type, env) |
+ |
+ return function |
+ |
+ if pos is not None: |
+ if len(bad_types) == 1: |
+ error(pos, bad_types[0][1]) |
+ else: |
+ error(pos, "no suitable method found") |
+ |
+ return None |
+ |
+def merge_template_deductions(a, b): |
+ if a is None or b is None: |
+ return None |
+ all = a |
+ for param, value in b.iteritems(): |
+ if param in all: |
+ if a[param] != b[param]: |
+ return None |
+ else: |
+ all[param] = value |
+ return all |
+ |
+def widest_numeric_type(type1, type2): |
+ # Given two numeric types, return the narrowest type |
+ # encompassing both of them. |
+ if type1 == type2: |
+ widest_type = type1 |
+ elif type1.is_complex or type2.is_complex: |
+ def real_type(ntype): |
+ if ntype.is_complex: |
+ return ntype.real_type |
+ return ntype |
+ widest_type = CComplexType( |
+ widest_numeric_type( |
+ real_type(type1), |
+ real_type(type2))) |
+ elif type1.is_enum and type2.is_enum: |
+ widest_type = c_int_type |
+ elif type1.rank < type2.rank: |
+ widest_type = type2 |
+ elif type1.rank > type2.rank: |
+ widest_type = type1 |
+ elif type1.signed < type2.signed: |
+ widest_type = type1 |
+ else: |
+ widest_type = type2 |
+ return widest_type |
+ |
+def independent_spanning_type(type1, type2): |
+ # Return a type assignable independently from both type1 and |
+ # type2, but do not require any interoperability between the two. |
+ # For example, in "True * 2", it is safe to assume an integer |
+ # result type (so spanning_type() will do the right thing), |
+ # whereas "x = True or 2" must evaluate to a type that can hold |
+ # both a boolean value and an integer, so this function works |
+ # better. |
+ if type1 == type2: |
+ return type1 |
+ elif (type1 is c_bint_type or type2 is c_bint_type) and (type1.is_numeric and type2.is_numeric): |
+ # special case: if one of the results is a bint and the other |
+ # is another C integer, we must prevent returning a numeric |
+ # type so that we do not lose the ability to coerce to a |
+ # Python bool if we have to. |
+ return py_object_type |
+ span_type = _spanning_type(type1, type2) |
+ if span_type is None: |
+ return error_type |
+ return span_type |
+ |
+def spanning_type(type1, type2): |
+ # Return a type assignable from both type1 and type2, or |
+ # py_object_type if no better type is found. Assumes that the |
+ # code that calls this will try a coercion afterwards, which will |
+ # fail if the types cannot actually coerce to a py_object_type. |
+ if type1 == type2: |
+ return type1 |
+ elif type1 is py_object_type or type2 is py_object_type: |
+ return py_object_type |
+ elif type1 is c_py_unicode_type or type2 is c_py_unicode_type: |
+ # Py_UNICODE behaves more like a string than an int |
+ return py_object_type |
+ span_type = _spanning_type(type1, type2) |
+ if span_type is None: |
+ return py_object_type |
+ return span_type |
+ |
+def _spanning_type(type1, type2): |
+ if type1.is_numeric and type2.is_numeric: |
+ return widest_numeric_type(type1, type2) |
+ elif type1.is_builtin_type and type1.name == 'float' and type2.is_numeric: |
+ return widest_numeric_type(c_double_type, type2) |
+ elif type2.is_builtin_type and type2.name == 'float' and type1.is_numeric: |
+ return widest_numeric_type(type1, c_double_type) |
+ elif type1.is_extension_type and type2.is_extension_type: |
+ return widest_extension_type(type1, type2) |
+ elif type1.is_pyobject or type2.is_pyobject: |
+ return py_object_type |
+ elif type1.assignable_from(type2): |
+ if type1.is_extension_type and type1.typeobj_is_imported(): |
+ # external types are unsafe, so we use PyObject instead |
+ return py_object_type |
+ return type1 |
+ elif type2.assignable_from(type1): |
+ if type2.is_extension_type and type2.typeobj_is_imported(): |
+ # external types are unsafe, so we use PyObject instead |
+ return py_object_type |
+ return type2 |
+ else: |
+ return None |
+ |
+def widest_extension_type(type1, type2): |
+ if type1.typeobj_is_imported() or type2.typeobj_is_imported(): |
+ return py_object_type |
+ while True: |
+ if type1.subtype_of(type2): |
+ return type2 |
+ elif type2.subtype_of(type1): |
+ return type1 |
+ type1, type2 = type1.base_type, type2.base_type |
+ if type1 is None or type2 is None: |
+ return py_object_type |
+ |
+def simple_c_type(signed, longness, name): |
+ # Find type descriptor for simple type given name and modifiers. |
+ # Returns None if arguments don't make sense. |
+ return modifiers_and_name_to_type.get((signed, longness, name)) |
+ |
+def parse_basic_type(name): |
+ base = None |
+ if name.startswith('p_'): |
+ base = parse_basic_type(name[2:]) |
+ elif name.startswith('p'): |
+ base = parse_basic_type(name[1:]) |
+ elif name.endswith('*'): |
+ base = parse_basic_type(name[:-1]) |
+ if base: |
+ return CPtrType(base) |
+ # |
+ basic_type = simple_c_type(1, 0, name) |
+ if basic_type: |
+ return basic_type |
+ # |
+ signed = 1 |
+ longness = 0 |
+ if name == 'Py_UNICODE': |
+ signed = 0 |
+ elif name == 'Py_UCS4': |
+ signed = 0 |
+ elif name == 'Py_hash_t': |
+ signed = 2 |
+ elif name == 'Py_ssize_t': |
+ signed = 2 |
+ elif name == 'ssize_t': |
+ signed = 2 |
+ elif name == 'size_t': |
+ signed = 0 |
+ else: |
+ if name.startswith('u'): |
+ name = name[1:] |
+ signed = 0 |
+ elif (name.startswith('s') and |
+ not name.startswith('short')): |
+ name = name[1:] |
+ signed = 2 |
+ longness = 0 |
+ while name.startswith('short'): |
+ name = name.replace('short', '', 1).strip() |
+ longness -= 1 |
+ while name.startswith('long'): |
+ name = name.replace('long', '', 1).strip() |
+ longness += 1 |
+ if longness != 0 and not name: |
+ name = 'int' |
+ return simple_c_type(signed, longness, name) |
+ |
+def c_array_type(base_type, size): |
+ # Construct a C array 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 error_type: |
+ return error_type |
+ else: |
+ return CPtrType(base_type) |
+ |
+def c_ref_type(base_type): |
+ # Construct a C reference type |
+ if base_type is error_type: |
+ return error_type |
+ else: |
+ return CReferenceType(base_type) |
+ |
+def c_const_type(base_type): |
+ # Construct a C const type. |
+ if base_type is error_type: |
+ return error_type |
+ else: |
+ return CConstType(base_type) |
+ |
+def same_type(type1, type2): |
+ return type1.same_as(type2) |
+ |
+def assignable_from(type1, type2): |
+ return type1.assignable_from(type2) |
+ |
+def typecast(to_type, from_type, expr_code): |
+ # Return expr_code cast to a C type which can be |
+ # assigned to to_type, assuming its existing C type |
+ # is from_type. |
+ if (to_type is from_type or |
+ (not to_type.is_pyobject and assignable_from(to_type, from_type))): |
+ return expr_code |
+ elif (to_type is py_object_type and from_type and |
+ from_type.is_builtin_type and from_type.name != 'type'): |
+ # no cast needed, builtins are PyObject* already |
+ return expr_code |
+ else: |
+ #print "typecast: to", to_type, "from", from_type ### |
+ return to_type.cast_code(expr_code) |