Example #1
0
    def copy_def(self, env):
        """
        Create a copy of the original def or lambda function for specialized
        versions.
        """
        fused_compound_types = PyrexTypes.unique(
            [arg.type for arg in self.node.args if arg.type.is_fused])
        permutations = PyrexTypes.get_all_specialized_permutations(fused_compound_types)

        self.fused_compound_types = fused_compound_types

        if self.node.entry in env.pyfunc_entries:
            env.pyfunc_entries.remove(self.node.entry)

        for cname, fused_to_specific in permutations:
            copied_node = copy.deepcopy(self.node)

            self._specialize_function_args(copied_node.args, fused_to_specific)
            copied_node.return_type = self.node.return_type.specialize(
                                                    fused_to_specific)

            copied_node.analyse_declarations(env)
            self.create_new_local_scope(copied_node, env, fused_to_specific)
            self.specialize_copied_def(copied_node, cname, self.node.entry,
                                       fused_to_specific, fused_compound_types)

            PyrexTypes.specialize_entry(copied_node.entry, cname)
            copied_node.entry.used = True
            env.entries[copied_node.entry.name] = copied_node.entry

            if not self.replace_fused_typechecks(copied_node):
                break

        self.orig_py_func = self.node
        self.py_func = self.make_fused_cpdef(self.node, env, is_def=True)
Example #2
0
    def specialize_copied_def(self, node, cname, py_entry, f2s, fused_types):
        """Specialize the copy of a DefNode given the copied node,
        the specialization cname and the original DefNode entry"""
        type_strings = [PyrexTypes.specialization_signature_string(fused_type, f2s) for fused_type in fused_types]

        node.specialized_signature_string = ", ".join(type_strings)

        node.entry.pymethdef_cname = PyrexTypes.get_fused_cname(cname, node.entry.pymethdef_cname)
        node.entry.doc = py_entry.doc
        node.entry.doc_cname = py_entry.doc_cname
    def test_cpp_reference_cpp_class(self):
        classes = [cppclasstype("Test%d" % i, []) for i in range(2)]
        function_types = [
            cfunctype(pt.CReferenceType(classes[0])),
            cfunctype(pt.CReferenceType(classes[1])),
        ]

        functions = [NameNode(None, type=t) for t in function_types]
        self.assertMatches(function_types[0], [classes[0]], functions)
        self.assertMatches(function_types[1], [classes[1]], functions)
    def test_cpp_reference_single_arg(self):
        function_types = [
            cfunctype(pt.CReferenceType(pt.c_int_type)),
            cfunctype(pt.CReferenceType(pt.c_long_type)),
            cfunctype(pt.CReferenceType(pt.c_double_type)),
        ]

        functions = [NameNode(None, type=t) for t in function_types]
        self.assertMatches(function_types[0], [pt.c_int_type], functions)
        self.assertMatches(function_types[1], [pt.c_long_type], functions)
        self.assertMatches(function_types[2], [pt.c_double_type], functions)
    def test_cpp_reference_cpp_class_and_int(self):
        classes = [cppclasstype("Test%d" % i, []) for i in range(2)]
        function_types = [
            cfunctype(pt.CReferenceType(classes[0]), pt.c_int_type),
            cfunctype(pt.CReferenceType(classes[0]), pt.c_long_type),
            cfunctype(pt.CReferenceType(classes[1]), pt.c_int_type),
            cfunctype(pt.CReferenceType(classes[1]), pt.c_long_type),
        ]

        functions = [NameNode(None, type=t) for t in function_types]
        self.assertMatches(function_types[0], [classes[0], pt.c_int_type], functions)
        self.assertMatches(function_types[1], [classes[0], pt.c_long_type], functions)
        self.assertMatches(function_types[2], [classes[1], pt.c_int_type], functions)
        self.assertMatches(function_types[3], [classes[1], pt.c_long_type], functions)
Example #6
0
    def specialize_copied_def(self, node, cname, py_entry, f2s, fused_types):
        """Specialize the copy of a DefNode given the copied node,
        the specialization cname and the original DefNode entry"""
        type_strings = [
            PyrexTypes.specialization_signature_string(fused_type, f2s)
            for fused_type in fused_types
        ]

        node.specialized_signature_string = '|'.join(type_strings)

        node.entry.pymethdef_cname = PyrexTypes.get_fused_cname(
            cname, node.entry.pymethdef_cname)
        node.entry.doc = py_entry.doc
        node.entry.doc_cname = py_entry.doc_cname
Example #7
0
    def test_widest_numeric_type(self):
        def assert_widest(type1, type2, widest):
            self.assertEqual(widest, PT.widest_numeric_type(type1, type2))

        assert_widest(PT.c_int_type, PT.c_long_type, PT.c_long_type)
        assert_widest(PT.c_double_type, PT.c_long_type, PT.c_double_type)
        assert_widest(PT.c_longdouble_type, PT.c_long_type,
                      PT.c_longdouble_type)

        cenum = PT.CEnumType("E", "cenum", typedef_flag=False)
        assert_widest(PT.c_int_type, cenum, PT.c_int_type)
Example #8
0
    def copy_def(self, env):
        """
        Create a copy of the original def or lambda function for specialized
        versions.
        """
        fused_compound_types = PyrexTypes.unique(
            [arg.type for arg in self.node.args if arg.type.is_fused])
        permutations = PyrexTypes.get_all_specialized_permutations(
            fused_compound_types)

        self.fused_compound_types = fused_compound_types

        if self.node.entry in env.pyfunc_entries:
            env.pyfunc_entries.remove(self.node.entry)

        for cname, fused_to_specific in permutations:
            copied_node = copy.deepcopy(self.node)

            self._specialize_function_args(copied_node.args, fused_to_specific)
            copied_node.return_type = self.node.return_type.specialize(
                fused_to_specific)

            copied_node.analyse_declarations(env)
            # copied_node.is_staticmethod = self.node.is_staticmethod
            # copied_node.is_classmethod = self.node.is_classmethod
            self.create_new_local_scope(copied_node, env, fused_to_specific)
            self.specialize_copied_def(copied_node, cname, self.node.entry,
                                       fused_to_specific, fused_compound_types)

            PyrexTypes.specialize_entry(copied_node.entry, cname)
            copied_node.entry.used = True
            env.entries[copied_node.entry.name] = copied_node.entry

            if not self.replace_fused_typechecks(copied_node):
                break

        self.orig_py_func = self.node
        self.py_func = self.make_fused_cpdef(self.node, env, is_def=True)
Example #9
0
    def _split_fused_types(self, arg):
        """
        Specialize fused types and split into normal types and buffer types.
        """
        specialized_types = PyrexTypes.get_specialized_types(arg.type)
        # Prefer long over int, etc
        # specialized_types.sort()
        seen_py_type_names = set()
        normal_types, buffer_types = [], []
        for specialized_type in specialized_types:
            py_type_name = specialized_type.py_type_name()
            if py_type_name:
                if py_type_name in seen_py_type_names:
                    continue
                seen_py_type_names.add(py_type_name)
                normal_types.append(specialized_type)
            elif specialized_type.is_buffer or specialized_type.is_memoryviewslice:
                buffer_types.append(specialized_type)

        return normal_types, buffer_types
Example #10
0
    def _split_fused_types(self, arg):
        """
        Specialize fused types and split into normal types and buffer types.
        """
        specialized_types = PyrexTypes.get_specialized_types(arg.type)
        # Prefer long over int, etc
        # specialized_types.sort()
        seen_py_type_names = set()
        normal_types, buffer_types = [], []
        for specialized_type in specialized_types:
            py_type_name = specialized_type.py_type_name()
            if py_type_name:
                if py_type_name in seen_py_type_names:
                    continue
                seen_py_type_names.add(py_type_name)
                normal_types.append(specialized_type)
            elif specialized_type.is_buffer or specialized_type.is_memoryviewslice:
                buffer_types.append(specialized_type)

        return normal_types, buffer_types
Example #11
0
    def _buffer_parse_format_string_check(self, pyx_code, decl_code,
                                          specialized_type, env):
        """
        For each specialized type, try to coerce the object to a memoryview
        slice of that type. This means obtaining a buffer and parsing the
        format string.
        TODO: separate buffer acquisition from format parsing
        """
        dtype = specialized_type.dtype
        if specialized_type.is_buffer:
            axes = [('direct', 'strided')] * specialized_type.ndim
        else:
            axes = specialized_type.axes

        memslice_type = PyrexTypes.MemoryViewSliceType(dtype, axes)
        memslice_type.create_from_py_utility_code(env)
        pyx_code.context.update(
            coerce_from_py_func=memslice_type.from_py_function, dtype=dtype)
        decl_code.putln(
            "{{memviewslice_cname}} {{coerce_from_py_func}}(object)")

        pyx_code.context.update(
            specialized_type_name=specialized_type.specialization_string,
            sizeof_dtype=self._sizeof_dtype(dtype))

        pyx_code.put_chunk(u"""
                # try {{dtype}}
                if itemsize == -1 or itemsize == {{sizeof_dtype}}:
                    memslice = {{coerce_from_py_func}}(arg)
                    if memslice.memview:
                        __PYX_XDEC_MEMVIEW(&memslice, 1)
                        # print 'found a match for the buffer through format parsing'
                        %s
                        break
                    else:
                        __pyx_PyErr_Clear()
            """ % self.match)
Example #12
0
def put_assign_to_buffer(lhs_cname, rhs_cname, buf_entry,
                         is_initialized, pos, code):
    """
    Generate code for reassigning a buffer variables. This only deals with getting
    the buffer auxiliary structure and variables set up correctly, the assignment
    itself and refcounting is the responsibility of the caller.

    However, the assignment operation may throw an exception so that the reassignment
    never happens.

    Depending on the circumstances there are two possible outcomes:
    - Old buffer released, new acquired, rhs assigned to lhs
    - Old buffer released, new acquired which fails, reaqcuire old lhs buffer
      (which may or may not succeed).
    """

    buffer_aux, buffer_type = buf_entry.buffer_aux, buf_entry.type
    code.globalstate.use_utility_code(acquire_utility_code)
    pybuffernd_struct = buffer_aux.buflocal_nd_var.cname
    flags = get_flags(buffer_aux, buffer_type)

    code.putln("{")  # Set up necesarry stack for getbuffer
    code.putln("__Pyx_BufFmt_StackElem __pyx_stack[%d];" % buffer_type.dtype.struct_nesting_depth())

    getbuffer = get_getbuffer_call(code, "%s", buffer_aux, buffer_type) # fill in object below

    if is_initialized:
        # Release any existing buffer
        code.putln('__Pyx_SafeReleaseBuffer(&%s.rcbuffer->pybuffer);' % pybuffernd_struct)
        # Acquire
        retcode_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False)
        code.putln("%s = %s;" % (retcode_cname, getbuffer % rhs_cname))
        code.putln('if (%s) {' % (code.unlikely("%s < 0" % retcode_cname)))
        # If acquisition failed, attempt to reacquire the old buffer
        # before raising the exception. A failure of reacquisition
        # will cause the reacquisition exception to be reported, one
        # can consider working around this later.
        type, value, tb = [code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=False)
                           for i in range(3)]
        code.putln('PyErr_Fetch(&%s, &%s, &%s);' % (type, value, tb))
        code.putln('if (%s) {' % code.unlikely("%s == -1" % (getbuffer % lhs_cname)))
        code.putln('Py_XDECREF(%s); Py_XDECREF(%s); Py_XDECREF(%s);' % (type, value, tb)) # Do not refnanny these!
        code.globalstate.use_utility_code(raise_buffer_fallback_code)
        code.putln('__Pyx_RaiseBufferFallbackError();')
        code.putln('} else {')
        code.putln('PyErr_Restore(%s, %s, %s);' % (type, value, tb))
        for t in (type, value, tb):
            code.funcstate.release_temp(t)
        code.putln('}')
        code.putln('}')
        # Unpack indices
        put_unpack_buffer_aux_into_scope(buf_entry, code)
        code.putln(code.error_goto_if_neg(retcode_cname, pos))
        code.funcstate.release_temp(retcode_cname)
    else:
        # Our entry had no previous value, so set to None when acquisition fails.
        # In this case, auxiliary vars should be set up right in initialization to a zero-buffer,
        # so it suffices to set the buf field to NULL.
        code.putln('if (%s) {' % code.unlikely("%s == -1" % (getbuffer % rhs_cname)))
        code.putln('%s = %s; __Pyx_INCREF(Py_None); %s.rcbuffer->pybuffer.buf = NULL;' %
                   (lhs_cname,
                    PyrexTypes.typecast(buffer_type, PyrexTypes.py_object_type, "Py_None"),
                    pybuffernd_struct))
        code.putln(code.error_goto(pos))
        code.put('} else {')
        # Unpack indices
        put_unpack_buffer_aux_into_scope(buf_entry, code)
        code.putln('}')

    code.putln("}") # Release stack
Example #13
0
File: Buffer.py Project: pv/cython
def put_assign_to_buffer(lhs_cname, rhs_cname, buf_entry, is_initialized, pos,
                         code):
    """
    Generate code for reassigning a buffer variables. This only deals with getting
    the buffer auxiliary structure and variables set up correctly, the assignment
    itself and refcounting is the responsibility of the caller.

    However, the assignment operation may throw an exception so that the reassignment
    never happens.

    Depending on the circumstances there are two possible outcomes:
    - Old buffer released, new acquired, rhs assigned to lhs
    - Old buffer released, new acquired which fails, reaqcuire old lhs buffer
      (which may or may not succeed).
    """

    buffer_aux, buffer_type = buf_entry.buffer_aux, buf_entry.type
    code.globalstate.use_utility_code(acquire_utility_code)
    pybuffernd_struct = buffer_aux.buflocal_nd_var.cname
    flags = get_flags(buffer_aux, buffer_type)

    code.putln("{")  # Set up necesarry stack for getbuffer
    code.putln("__Pyx_BufFmt_StackElem __pyx_stack[%d];" %
               buffer_type.dtype.struct_nesting_depth())

    getbuffer = get_getbuffer_call(code, "%s", buffer_aux,
                                   buffer_type)  # fill in object below

    if is_initialized:
        # Release any existing buffer
        code.putln('__Pyx_SafeReleaseBuffer(&%s.rcbuffer->pybuffer);' %
                   pybuffernd_struct)
        # Acquire
        retcode_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type,
                                                     manage_ref=False)
        code.putln("%s = %s;" % (retcode_cname, getbuffer % rhs_cname))
        code.putln('if (%s) {' % (code.unlikely("%s < 0" % retcode_cname)))
        # If acquisition failed, attempt to reacquire the old buffer
        # before raising the exception. A failure of reacquisition
        # will cause the reacquisition exception to be reported, one
        # can consider working around this later.
        type, value, tb = [
            code.funcstate.allocate_temp(PyrexTypes.py_object_type,
                                         manage_ref=False) for i in range(3)
        ]
        code.putln('PyErr_Fetch(&%s, &%s, &%s);' % (type, value, tb))
        code.putln('if (%s) {' % code.unlikely("%s == -1" %
                                               (getbuffer % lhs_cname)))
        code.putln('Py_XDECREF(%s); Py_XDECREF(%s); Py_XDECREF(%s);' %
                   (type, value, tb))  # Do not refnanny these!
        code.globalstate.use_utility_code(raise_buffer_fallback_code)
        code.putln('__Pyx_RaiseBufferFallbackError();')
        code.putln('} else {')
        code.putln('PyErr_Restore(%s, %s, %s);' % (type, value, tb))
        for t in (type, value, tb):
            code.funcstate.release_temp(t)
        code.putln('}')
        code.putln('}')
        # Unpack indices
        put_unpack_buffer_aux_into_scope(buf_entry, code)
        code.putln(code.error_goto_if_neg(retcode_cname, pos))
        code.funcstate.release_temp(retcode_cname)
    else:
        # Our entry had no previous value, so set to None when acquisition fails.
        # In this case, auxiliary vars should be set up right in initialization to a zero-buffer,
        # so it suffices to set the buf field to NULL.
        code.putln('if (%s) {' % code.unlikely("%s == -1" %
                                               (getbuffer % rhs_cname)))
        code.putln(
            '%s = %s; __Pyx_INCREF(Py_None); %s.rcbuffer->pybuffer.buf = NULL;'
            % (lhs_cname,
               PyrexTypes.typecast(buffer_type, PyrexTypes.py_object_type,
                                   "Py_None"), pybuffernd_struct))
        code.putln(code.error_goto(pos))
        code.put('} else {')
        # Unpack indices
        put_unpack_buffer_aux_into_scope(buf_entry, code)
        code.putln('}')

    code.putln("}")  # Release stack
def cfunctype(*arg_types):
    return pt.CFuncType(pt.c_int_type,
                        [CFuncTypeArg("name", arg_type, None) for arg_type in arg_types])
 def assertMatches(self, expected_type, arg_types, functions):
     match = pt.best_match(arg_types, functions)
     if expected_type is not None:
         self.assertNotEqual(None, match)
     self.assertEqual(expected_type, match.type)
Example #16
0
 def assertMatches(self, expected_type, arg_types, functions):
     args = [ NameNode(None, type=arg_type) for arg_type in arg_types ]
     match = pt.best_match(args, functions)
     if expected_type is not None:
         self.assertNotEqual(None, match)
     self.assertEqual(expected_type, match.type)
 def assertMatches(self, expected_type, arg_types, functions):
     match = pt.best_match(arg_types, functions)
     if expected_type is not None:
         self.assertNotEqual(None, match)
     self.assertEqual(expected_type, match.type)
Example #18
0
 def assert_widest(type1, type2, widest):
     self.assertEqual(widest, PT.widest_numeric_type(type1, type2))
def cppclasstype(name, base_classes):
    return pt.CppClassType(name, None, 'CPP_' + name, base_classes)
Example #20
0
 def assert_widest(type1, type2, widest):
     self.assertEqual(widest, PT.widest_numeric_type(type1, type2))