Commit 01b003b1 authored by Stefan Behnel's avatar Stefan Behnel

rewrite of dict iteration code at a more C-ish level in order to make the...

rewrite of dict iteration code at a more C-ish level in order to make the actual code C compile time dependent

--HG--
extra : transplant_source : R%BCF%17%5D%7E%FA%B3%C4q%D2%28%CF%0Di%8D%FC%0B%E4%7B
parent 131ab175
...@@ -9752,25 +9752,9 @@ static CYTHON_INLINE int __Pyx_ErrOccurredWithGIL(void) { ...@@ -9752,25 +9752,9 @@ static CYTHON_INLINE int __Pyx_ErrOccurredWithGIL(void) {
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
raise_noneattr_error_utility_code = UtilityCode( raise_noneattr_error_utility_code = UtilityCode.load_cached("RaiseNoneAttrError", "ObjectHandling.c")
proto = """ raise_noneindex_error_utility_code = UtilityCode.load_cached("RaiseNoneIndexingError", "ObjectHandling.c")
static CYTHON_INLINE void __Pyx_RaiseNoneAttributeError(const char* attrname); raise_none_iter_error_utility_code = UtilityCode.load_cached("RaiseNoneIterError", "ObjectHandling.c")
""",
impl = '''
static CYTHON_INLINE void __Pyx_RaiseNoneAttributeError(const char* attrname) {
PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%s'", attrname);
}
''')
raise_noneindex_error_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE void __Pyx_RaiseNoneIndexingError(void);
""",
impl = '''
static CYTHON_INLINE void __Pyx_RaiseNoneIndexingError(void) {
PyErr_SetString(PyExc_TypeError, "'NoneType' object is unsubscriptable");
}
''')
raise_noneindex_memview_error_utility_code = UtilityCode( raise_noneindex_memview_error_utility_code = UtilityCode(
proto = """ proto = """
...@@ -9782,16 +9766,6 @@ static CYTHON_INLINE void __Pyx_RaiseNoneMemviewIndexingError(void) { ...@@ -9782,16 +9766,6 @@ static CYTHON_INLINE void __Pyx_RaiseNoneMemviewIndexingError(void) {
} }
''') ''')
raise_none_iter_error_utility_code = UtilityCode(
proto = """
static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void);
""",
impl = '''
static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) {
PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable");
}
''')
raise_unbound_local_error_utility_code = UtilityCode( raise_unbound_local_error_utility_code = UtilityCode(
proto = """ proto = """
static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname); static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname);
...@@ -10029,92 +10003,14 @@ impl = """ ...@@ -10029,92 +10003,14 @@ impl = """
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
raise_too_many_values_to_unpack = UtilityCode( raise_too_many_values_to_unpack = UtilityCode.load_cached("RaiseTooManyValuesToUnpack", "ObjectHandling.c")
proto = """ raise_need_more_values_to_unpack = UtilityCode.load_cached("RaiseNeedMoreValuesToUnpack", "ObjectHandling.c")
static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected);
""",
impl = '''
static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) {
PyErr_Format(PyExc_ValueError,
"too many values to unpack (expected %"PY_FORMAT_SIZE_T"d)", expected);
}
''')
raise_need_more_values_to_unpack = UtilityCode(
proto = """
static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index);
""",
impl = '''
static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) {
PyErr_Format(PyExc_ValueError,
"need more than %"PY_FORMAT_SIZE_T"d value%s to unpack",
index, (index == 1) ? "" : "s");
}
''')
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
tuple_unpacking_error_code = UtilityCode( tuple_unpacking_error_code = UtilityCode.load_cached("UnpackTupleError", "ObjectHandling.c")
proto = """ unpacking_utility_code = UtilityCode.load_cached("UnpackItem", "ObjectHandling.c")
static void __Pyx_UnpackTupleError(PyObject *, Py_ssize_t index); /*proto*/ iternext_unpacking_end_utility_code = UtilityCode.load_cached("UnpackItemEndCheck", "ObjectHandling.c")
""",
impl = """
static void __Pyx_UnpackTupleError(PyObject *t, Py_ssize_t index) {
if (t == Py_None) {
__Pyx_RaiseNoneNotIterableError();
} else if (PyTuple_GET_SIZE(t) < index) {
__Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(t));
} else {
__Pyx_RaiseTooManyValuesError(index);
}
}
""",
requires = [raise_none_iter_error_utility_code,
raise_need_more_values_to_unpack,
raise_too_many_values_to_unpack]
)
unpacking_utility_code = UtilityCode(
proto = """
static PyObject *__Pyx_UnpackItem(PyObject *, Py_ssize_t index); /*proto*/
""",
impl = """
static PyObject *__Pyx_UnpackItem(PyObject *iter, Py_ssize_t index) {
PyObject *item;
if (!(item = PyIter_Next(iter))) {
if (!PyErr_Occurred()) {
__Pyx_RaiseNeedMoreValuesError(index);
}
}
return item;
}
""",
requires = [raise_need_more_values_to_unpack]
)
iternext_unpacking_end_utility_code = UtilityCode(
proto = """
static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected); /*proto*/
""",
impl = """
static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected) {
if (unlikely(retval)) {
Py_DECREF(retval);
__Pyx_RaiseTooManyValuesError(expected);
return -1;
} else if (PyErr_Occurred()) {
if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) {
PyErr_Clear();
return 0;
} else {
return -1;
}
}
return 0;
}
""",
requires = [raise_too_many_values_to_unpack]
)
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
......
...@@ -5772,45 +5772,98 @@ class DictIterationNextNode(Node): ...@@ -5772,45 +5772,98 @@ class DictIterationNextNode(Node):
# Helper node for calling PyDict_Next() inside of a WhileStatNode # Helper node for calling PyDict_Next() inside of a WhileStatNode
# and checking the dictionary size for changes. Created in # and checking the dictionary size for changes. Created in
# Optimize.py. # Optimize.py.
child_attrs = ['dict_obj', 'expected_size', 'pos_index_addr', 'key_addr', 'value_addr'] child_attrs = ['dict_obj', 'expected_size', 'pos_index_var',
'coerced_key_var', 'coerced_value_var', 'coerced_tuple_var',
'key_target', 'value_target', 'tuple_target', 'is_dict_flag']
def __init__(self, dict_obj, expected_size, pos_index_addr, key_addr, value_addr): coerced_key_var = key_ref = None
coerced_value_var = value_ref = None
coerced_tuple_var = tuple_ref = None
def __init__(self, dict_obj, expected_size, pos_index_var,
key_target, value_target, tuple_target, is_dict_flag):
Node.__init__( Node.__init__(
self, dict_obj.pos, self, dict_obj.pos,
dict_obj = dict_obj, dict_obj = dict_obj,
expected_size = expected_size, expected_size = expected_size,
pos_index_addr = pos_index_addr, pos_index_var = pos_index_var,
key_addr = key_addr, key_target = key_target,
value_addr = value_addr, value_target = value_target,
tuple_target = tuple_target,
is_dict_flag = is_dict_flag,
is_temp = True,
type = PyrexTypes.c_bint_type) type = PyrexTypes.c_bint_type)
def analyse_expressions(self, env): def analyse_expressions(self, env):
import UtilNodes
self.dict_obj.analyse_types(env) self.dict_obj.analyse_types(env)
self.expected_size.analyse_types(env) self.expected_size.analyse_types(env)
self.pos_index_addr.analyse_types(env) if self.pos_index_var: self.pos_index_var.analyse_types(env)
self.key_addr.analyse_types(env) if self.key_target:
self.value_addr.analyse_types(env) self.key_target.analyse_target_types(env)
self.key_ref = UtilNodes.ResultRefNode(pos=self.key_target.pos, is_temp=True,
type=PyrexTypes.py_object_type)
self.coerced_key_var = self.key_ref.coerce_to(self.key_target.type, env)
if self.value_target:
self.value_target.analyse_target_types(env)
self.value_ref = UtilNodes.ResultRefNode(pos=self.value_target.pos, is_temp=True,
type=PyrexTypes.py_object_type)
self.coerced_value_var = self.value_ref.coerce_to(self.value_target.type, env)
if self.tuple_target:
self.tuple_target.analyse_target_types(env)
self.tuple_ref = UtilNodes.ResultRefNode(pos=self.tuple_target.pos, is_temp=True,
type=PyrexTypes.py_object_type)
self.coerced_tuple_var = self.tuple_ref.coerce_to(self.tuple_target.type, env)
self.is_dict_flag.analyse_types(env)
def generate_function_definitions(self, env, code): def generate_function_definitions(self, env, code):
self.dict_obj.generate_function_definitions(env, code) self.dict_obj.generate_function_definitions(env, code)
def generate_execution_code(self, code): def generate_execution_code(self, code):
code.globalstate.use_utility_code(UtilityCode.load_cached("dict_iter", "Optimize.c"))
self.dict_obj.generate_evaluation_code(code) self.dict_obj.generate_evaluation_code(code)
code.putln("if (unlikely(%s != PyDict_Size(%s))) {" % (
self.expected_size.result(), assignments = []
temp_addresses = []
for var, result, target in [(self.key_ref, self.coerced_key_var, self.key_target),
(self.value_ref, self.coerced_value_var, self.value_target),
(self.tuple_ref, self.coerced_tuple_var, self.tuple_target)]:
if target is None:
addr = 'NULL'
else:
temp = code.funcstate.allocate_temp(PyrexTypes.py_object_type, True)
var.result_code = temp
assignments.append((temp, result, target))
addr = '&%s' % temp
temp_addresses.append(addr)
result_temp = code.funcstate.allocate_temp(PyrexTypes.c_int_type, False)
code.putln("%s = __Pyx_dict_iter_next(%s, %s, &%s, %s, %s, %s, %s);" % (
result_temp,
self.dict_obj.py_result(), self.dict_obj.py_result(),
self.expected_size.result(),
self.pos_index_var.result(),
temp_addresses[0],
temp_addresses[1],
temp_addresses[2],
self.is_dict_flag.result()
)) ))
code.putln('PyErr_SetString(PyExc_RuntimeError, "dictionary changed size during iteration"); %s' % ( code.putln("if (unlikely(%s == 0)) break;" % result_temp)
code.error_goto(self.pos))) code.putln(code.error_goto_if("%s == -1" % result_temp, self.pos))
code.putln("}") code.funcstate.release_temp(result_temp)
self.pos_index_addr.generate_evaluation_code(code)
code.putln("if (!PyDict_Next(%s, %s, %s, %s)) break;" % ( # evaluate all coercions before the assignments
self.dict_obj.py_result(), for temp, result, target in assignments:
self.pos_index_addr.result(), code.put_gotref(temp)
self.key_addr.result(), result.generate_evaluation_code(code)
self.value_addr.result())) if not result.type.is_pyobject:
code.put_decref_clear(temp, PyrexTypes.py_object_type)
code.funcstate.release_temp(temp)
for temp, result, target in assignments:
target.generate_assignment_code(result, code)
if result.type.is_pyobject:
code.funcstate.release_temp(temp)
def ForStatNode(pos, **kw): def ForStatNode(pos, **kw):
if 'iterator' in kw: if 'iterator' in kw:
......
...@@ -152,7 +152,7 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -152,7 +152,7 @@ class IterationTransform(Visitor.VisitorTransform):
# CPython raises an error here: not a sequence # CPython raises an error here: not a sequence
return node return node
return self._transform_dict_iteration( return self._transform_dict_iteration(
node, dict_obj=iterator, keys=True, values=False) node, dict_obj=iterator, method=None, keys=True, values=False)
# C array (slice) iteration? # C array (slice) iteration?
if iterator.type.is_ptr or iterator.type.is_array: if iterator.type.is_ptr or iterator.type.is_array:
...@@ -185,7 +185,7 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -185,7 +185,7 @@ class IterationTransform(Visitor.VisitorTransform):
else: else:
return node return node
return self._transform_dict_iteration( return self._transform_dict_iteration(
node, dict_obj, keys, values) node, dict_obj, method, keys, values)
# enumerate/reversed ? # enumerate/reversed ?
if iterator.self is None and function.is_name and \ if iterator.self is None and function.is_name and \
...@@ -607,9 +607,7 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -607,9 +607,7 @@ class IterationTransform(Visitor.VisitorTransform):
return for_node return for_node
def _transform_dict_iteration(self, node, dict_obj, keys, values): def _transform_dict_iteration(self, node, dict_obj, method, keys, values):
py_object_ptr = PyrexTypes.py_object_type
temps = [] temps = []
temp = UtilNodes.TempHandle(PyrexTypes.py_object_type) temp = UtilNodes.TempHandle(PyrexTypes.py_object_type)
temps.append(temp) temps.append(temp)
...@@ -617,36 +615,8 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -617,36 +615,8 @@ class IterationTransform(Visitor.VisitorTransform):
temp = UtilNodes.TempHandle(PyrexTypes.c_py_ssize_t_type) temp = UtilNodes.TempHandle(PyrexTypes.c_py_ssize_t_type)
temps.append(temp) temps.append(temp)
pos_temp = temp.ref(node.pos) pos_temp = temp.ref(node.pos)
pos_temp_addr = ExprNodes.AmpersandNode(
node.pos, operand=pos_temp, key_target = value_target = tuple_target = None
type=PyrexTypes.c_ptr_type(PyrexTypes.c_py_ssize_t_type))
target_temps = []
if keys:
temp = UtilNodes.TempHandle(
py_object_ptr, needs_cleanup=False) # ref will be stolen
target_temps.append(temp)
key_temp = temp.ref(node.target.pos)
key_temp_addr = ExprNodes.AmpersandNode(
node.target.pos, operand=key_temp,
type=PyrexTypes.c_ptr_type(py_object_ptr))
else:
key_temp_addr = key_temp = ExprNodes.NullNode(
pos=node.target.pos)
if values:
temp = UtilNodes.TempHandle(
py_object_ptr, needs_cleanup=False) # ref will be stolen
target_temps.append(temp)
value_temp = temp.ref(node.target.pos)
value_temp_addr = ExprNodes.AmpersandNode(
node.target.pos, operand=value_temp,
type=PyrexTypes.c_ptr_type(py_object_ptr))
else:
value_temp_addr = value_temp = ExprNodes.NullNode(
pos=node.target.pos)
key_target = value_target = node.target
tuple_target = None
if keys and values: if keys and values:
if node.target.is_sequence_constructor: if node.target.is_sequence_constructor:
if len(node.target.args) == 2: if len(node.target.args) == 2:
...@@ -656,67 +626,10 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -656,67 +626,10 @@ class IterationTransform(Visitor.VisitorTransform):
return node return node
else: else:
tuple_target = node.target tuple_target = node.target
elif keys:
def coerce_object_to(obj_node, dest_type): key_target = node.target
if dest_type.is_pyobject:
if dest_type != obj_node.type:
if dest_type.is_extension_type or dest_type.is_builtin_type:
obj_node = ExprNodes.PyTypeTestNode(
obj_node, dest_type, self.current_scope, notnone=True)
result = ExprNodes.TypecastNode(
obj_node.pos,
operand = obj_node,
type = dest_type)
return (result, None)
else:
temp = UtilNodes.TempHandle(dest_type)
target_temps.append(temp)
temp_result = temp.ref(obj_node.pos)
class CoercedTempNode(ExprNodes.CoerceFromPyTypeNode):
def result(self):
return temp_result.result()
def generate_execution_code(self, code):
self.generate_result_code(code)
return (temp_result, CoercedTempNode(dest_type, obj_node, self.current_scope))
if tuple_target:
tuple_result = ExprNodes.TupleNode(
pos = tuple_target.pos,
args = [key_temp, value_temp],
is_temp = 1,
type = Builtin.tuple_type,
)
body_init_stats = [
Nodes.SingleAssignmentNode(
pos = tuple_target.pos,
lhs = tuple_target,
rhs = tuple_result)
]
else: else:
# execute all coercions before the assignments value_target = node.target
coercion_stats = []
assign_stats = []
if keys:
temp_result, coercion = coerce_object_to(
key_temp, key_target.type)
if coercion:
coercion_stats.append(coercion)
assign_stats.append(
Nodes.SingleAssignmentNode(
pos = key_temp.pos,
lhs = key_target,
rhs = temp_result))
if values:
temp_result, coercion = coerce_object_to(
value_temp, value_target.type)
if coercion:
coercion_stats.append(coercion)
assign_stats.append(
Nodes.SingleAssignmentNode(
pos = value_temp.pos,
lhs = value_target,
rhs = temp_result))
body_init_stats = coercion_stats + assign_stats
if isinstance(node.body, Nodes.StatListNode): if isinstance(node.body, Nodes.StatListNode):
body = node.body body = node.body
...@@ -727,24 +640,39 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -727,24 +640,39 @@ class IterationTransform(Visitor.VisitorTransform):
# keep original length to guard against dict modification # keep original length to guard against dict modification
dict_len_temp = UtilNodes.TempHandle(PyrexTypes.c_py_ssize_t_type) dict_len_temp = UtilNodes.TempHandle(PyrexTypes.c_py_ssize_t_type)
temps.append(dict_len_temp) temps.append(dict_len_temp)
dict_len_temp_addr = ExprNodes.AmpersandNode(
node.pos, operand=dict_len_temp.ref(dict_obj.pos),
type=PyrexTypes.c_ptr_type(dict_len_temp.type))
temp = UtilNodes.TempHandle(PyrexTypes.c_int_type)
temps.append(temp)
is_dict_temp = temp.ref(node.pos)
is_dict_temp_addr = ExprNodes.AmpersandNode(
node.pos, operand=is_dict_temp,
type=PyrexTypes.c_ptr_type(temp.type))
iter_next_node = Nodes.DictIterationNextNode(
dict_temp, dict_len_temp.ref(dict_obj.pos), pos_temp,
key_target, value_target, tuple_target,
is_dict_temp)
iter_next_node.analyse_expressions(self.current_scope)
body.stats[0:0] = [iter_next_node]
if method:
method_node = ExprNodes.StringNode(
dict_obj.pos, is_identifier=True, value=method)
dict_obj = dict_obj.as_none_safe_node(
"'NoneType' object has no attribute '%s'",
error = "PyExc_AttributeError",
format_args = [method])
else:
method_node = ExprNodes.NullNode(dict_obj.pos)
dict_obj = dict_obj.as_none_safe_node("'NoneType' object is not iterable")
body_init_stats.insert(0, Nodes.DictIterationNextNode( def flag_node(value):
dict_temp, value = value and 1 or 0
dict_len_temp.ref(dict_obj.pos), return ExprNodes.IntNode(node.pos, value=str(value), constant_result=value)
pos_temp_addr, key_temp_addr, value_temp_addr
))
body.stats[0:0] = [UtilNodes.TempsBlockNode(
node.pos,
temps = target_temps,
body = Nodes.StatListNode(pos = node.pos,
stats = body_init_stats)
)]
result_code = [ result_code = [
Nodes.SingleAssignmentNode(
pos = dict_obj.pos,
lhs = dict_temp,
rhs = dict_obj),
Nodes.SingleAssignmentNode( Nodes.SingleAssignmentNode(
pos = node.pos, pos = node.pos,
lhs = pos_temp, lhs = pos_temp,
...@@ -752,16 +680,17 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -752,16 +680,17 @@ class IterationTransform(Visitor.VisitorTransform):
constant_result=0)), constant_result=0)),
Nodes.SingleAssignmentNode( Nodes.SingleAssignmentNode(
pos = dict_obj.pos, pos = dict_obj.pos,
lhs = dict_len_temp.ref(dict_obj.pos), lhs = dict_temp,
rhs = ExprNodes.SimpleCallNode( rhs = ExprNodes.PythonCapiCallNode(
pos = dict_obj.pos, dict_obj.pos,
type = PyrexTypes.c_py_ssize_t_type, "__Pyx_dict_iterator",
function = ExprNodes.NameNode( self.PyDict_Iterator_func_type,
pos = dict_obj.pos, utility_code = UtilityCode.load_cached("dict_iter", "Optimize.c"),
name = self.PyDict_Size_name, args = [dict_obj, flag_node(keys), flag_node(values),
type = self.PyDict_Size_func_type, flag_node(dict_obj.type is Builtin.dict_type),
entry = self.PyDict_Size_entry), method_node, dict_len_temp_addr, is_dict_temp_addr,
args = [dict_temp], ],
is_temp=True,
)), )),
Nodes.WhileStatNode( Nodes.WhileStatNode(
pos = node.pos, pos = node.pos,
...@@ -778,6 +707,17 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -778,6 +707,17 @@ class IterationTransform(Visitor.VisitorTransform):
stats = result_code stats = result_code
)) ))
PyDict_Iterator_func_type = PyrexTypes.CFuncType(
PyrexTypes.py_object_type, [
PyrexTypes.CFuncTypeArg("dict", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("keys", PyrexTypes.c_int_type, None),
PyrexTypes.CFuncTypeArg("values", PyrexTypes.c_int_type, None),
PyrexTypes.CFuncTypeArg("is_dict", PyrexTypes.c_int_type, None),
PyrexTypes.CFuncTypeArg("method_name", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("p_orig_length", PyrexTypes.c_py_ssize_t_ptr_type, None),
PyrexTypes.CFuncTypeArg("p_is_dict", PyrexTypes.c_int_ptr_type, None),
])
class SwitchTransform(Visitor.VisitorTransform): class SwitchTransform(Visitor.VisitorTransform):
""" """
......
...@@ -120,7 +120,7 @@ class ResultRefNode(AtomicExprNode): ...@@ -120,7 +120,7 @@ class ResultRefNode(AtomicExprNode):
subexprs = [] subexprs = []
lhs_of_first_assignment = False lhs_of_first_assignment = False
def __init__(self, expression=None, pos=None, type=None, may_hold_none=True): def __init__(self, expression=None, pos=None, type=None, may_hold_none=True, is_temp=False):
self.expression = expression self.expression = expression
self.pos = None self.pos = None
self.may_hold_none = may_hold_none self.may_hold_none = may_hold_none
...@@ -132,6 +132,8 @@ class ResultRefNode(AtomicExprNode): ...@@ -132,6 +132,8 @@ class ResultRefNode(AtomicExprNode):
self.pos = pos self.pos = pos
if type is not None: if type is not None:
self.type = type self.type = type
if is_temp:
self.is_temp = True
assert self.pos is not None assert self.pos is not None
def clone_node(self): def clone_node(self):
......
/////////////// RaiseNoneAttrError.proto ///////////////
static CYTHON_INLINE void __Pyx_RaiseNoneAttributeError(const char* attrname);
/////////////// RaiseNoneAttrError ///////////////
static CYTHON_INLINE void __Pyx_RaiseNoneAttributeError(const char* attrname) {
PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%s'", attrname);
}
/////////////// RaiseNoneIndexingError.proto ///////////////
static CYTHON_INLINE void __Pyx_RaiseNoneIndexingError(void);
/////////////// RaiseNoneIndexingError ///////////////
static CYTHON_INLINE void __Pyx_RaiseNoneIndexingError(void) {
PyErr_SetString(PyExc_TypeError, "'NoneType' object is unsubscriptable");
}
/////////////// RaiseNoneIterError.proto ///////////////
static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void);
/////////////// RaiseNoneIterError ///////////////
static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) {
PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable");
}
/////////////// RaiseTooManyValuesToUnpack.proto ///////////////
static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected);
/////////////// RaiseTooManyValuesToUnpack ///////////////
static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected) {
PyErr_Format(PyExc_ValueError,
"too many values to unpack (expected %"PY_FORMAT_SIZE_T"d)", expected);
}
/////////////// RaiseNeedMoreValuesToUnpack.proto ///////////////
static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index);
/////////////// RaiseNeedMoreValuesToUnpack ///////////////
static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) {
PyErr_Format(PyExc_ValueError,
"need more than %"PY_FORMAT_SIZE_T"d value%s to unpack",
index, (index == 1) ? "" : "s");
}
/////////////// UnpackTupleError.proto ///////////////
static void __Pyx_UnpackTupleError(PyObject *, Py_ssize_t index); /*proto*/
/////////////// UnpackTupleError ///////////////
//@requires: RaiseNoneIterError
//@requires: RaiseNeedMoreValuesToUnpack
//@requires: RaiseTooManyValuesToUnpack
static void __Pyx_UnpackTupleError(PyObject *t, Py_ssize_t index) {
if (t == Py_None) {
__Pyx_RaiseNoneNotIterableError();
} else if (PyTuple_GET_SIZE(t) < index) {
__Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(t));
} else {
__Pyx_RaiseTooManyValuesError(index);
}
}
/////////////// UnpackItem.proto ///////////////
static PyObject *__Pyx_UnpackItem(PyObject *, Py_ssize_t index); /*proto*/
/////////////// UnpackItem ///////////////
//@requires: RaiseNeedMoreValuesToUnpack
static PyObject *__Pyx_UnpackItem(PyObject *iter, Py_ssize_t index) {
PyObject *item;
if (!(item = PyIter_Next(iter))) {
if (!PyErr_Occurred()) {
__Pyx_RaiseNeedMoreValuesError(index);
}
}
return item;
}
/////////////// UnpackItemEndCheck.proto ///////////////
static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected); /*proto*/
/////////////// UnpackItemEndCheck ///////////////
//@requires: RaiseTooManyValuesToUnpack
static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected) {
if (unlikely(retval)) {
Py_DECREF(retval);
__Pyx_RaiseTooManyValuesError(expected);
return -1;
} else if (PyErr_Occurred()) {
if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) {
PyErr_Clear();
return 0;
} else {
return -1;
}
}
return 0;
}
/////////////// UnpackTuple2.proto ///////////////
static CYTHON_INLINE int __Pyx_unpack_tuple2(PyObject* tuple, PyObject** value1, PyObject** value2,
int is_tuple, int has_known_size, int decref_tuple);
/////////////// UnpackTuple2 ///////////////
//@requires: UnpackItem
//@requires: UnpackItemEndCheck
//@requires: UnpackTupleError
static CYTHON_INLINE int __Pyx_unpack_tuple2(PyObject* tuple, PyObject** pvalue1, PyObject** pvalue2,
int is_tuple, int has_known_size, int decref_tuple) {
PyObject *value1 = NULL, *value2 = NULL, *iter = NULL;
if (!is_tuple && unlikely(!PyTuple_Check(tuple))) {
iter = PyObject_GetIter(tuple);
if (unlikely(!iter)) goto bad;
if (decref_tuple)
Py_DECREF(tuple);
value1 = __Pyx_UnpackItem(iter, 0);
if (unlikely(!value1)) goto bad;
value2 = __Pyx_UnpackItem(iter, 1);
if (unlikely(!value2)) goto bad;
if (!has_known_size && unlikely(__Pyx_IternextUnpackEndCheck(PyIter_Next(iter), 2))) goto bad;
Py_DECREF(iter);
} else {
if (!has_known_size && unlikely(PyTuple_GET_SIZE(tuple) != 2)) {
__Pyx_UnpackTupleError(tuple, 2);
goto bad;
}
value1 = PyTuple_GET_ITEM(tuple, 0);
value2 = PyTuple_GET_ITEM(tuple, 1);
#if CYTHON_COMPILING_IN_CPYTHON
if (decref_tuple) {
PyTuple_SET_ITEM(tuple, 0, NULL);
PyTuple_SET_ITEM(tuple, 1, NULL);
} else
#endif
{
Py_INCREF(value1);
Py_INCREF(value2);
}
if (decref_tuple)
Py_DECREF(tuple);
}
*pvalue1 = value1;
*pvalue2 = value2;
return 0;
bad:
Py_XDECREF(iter);
Py_XDECREF(value1);
Py_XDECREF(value2);
if (decref_tuple) Py_DECREF(tuple);
return -1;
}
...@@ -299,6 +299,87 @@ static CYTHON_INLINE PyObject* __Pyx_PyDict_Clear(PyObject* d) { ...@@ -299,6 +299,87 @@ static CYTHON_INLINE PyObject* __Pyx_PyDict_Clear(PyObject* d) {
return Py_None; return Py_None;
} }
/////////////// dict_iter.proto ///////////////
static CYTHON_INLINE PyObject* __Pyx_dict_iterator(PyObject* dict, int keys, int values, int is_dict,
PyObject* method_name, Py_ssize_t* p_orig_length, int* p_is_dict);
static CYTHON_INLINE int __Pyx_dict_iter_next(PyObject* dict_or_iter, Py_ssize_t orig_length, Py_ssize_t* ppos,
PyObject** pkey, PyObject** pvalue, PyObject** pitem, int is_dict);
/////////////// dict_iter ///////////////
//@requires: ObjectHandling.c::UnpackTuple2
static CYTHON_INLINE PyObject* __Pyx_dict_iterator(PyObject* dict, int keys, int values, int is_dict,
PyObject* method_name, Py_ssize_t* p_orig_length, int* p_is_dict) {
#if !CYTHON_COMPILING_IN_PYPY
if (is_dict || likely(PyDict_CheckExact(dict))) {
*p_is_dict = 1;
*p_orig_length = PyDict_Size(dict);
Py_INCREF(dict);
return dict;
}
#endif
*p_is_dict = 0;
if (!method_name) {
return PyObject_GetIter(dict);
} else {
return PyObject_CallMethodObjArgs(dict, method_name, NULL);
}
}
static CYTHON_INLINE int __Pyx_dict_iter_next(PyObject* dict_or_iter, Py_ssize_t orig_length, Py_ssize_t* ppos,
PyObject** pkey, PyObject** pvalue, PyObject** pitem, int is_dict) {
#if !CYTHON_COMPILING_IN_PYPY
if (is_dict) {
PyObject *key, *value;
if (unlikely(orig_length != PyDict_Size(dict_or_iter))) {
PyErr_SetString(PyExc_RuntimeError, "dictionary changed size during iteration");
return -1;
}
if (unlikely(!PyDict_Next(dict_or_iter, ppos, &key, &value))) {
return 0;
}
if (pitem) {
PyObject* tuple = PyTuple_New(2);
if (unlikely(!tuple)) {
return -1;
}
Py_INCREF(key);
Py_INCREF(value);
PyTuple_SET_ITEM(tuple, 0, key);
PyTuple_SET_ITEM(tuple, 1, value);
*pitem = tuple;
} else {
if (pkey) {
Py_INCREF(key);
*pkey = key;
}
if (pvalue) {
Py_INCREF(value);
*pvalue = value;
}
}
return 1;
}
#endif
{
PyObject* next_item = PyIter_Next(dict_or_iter);
if (unlikely(!next_item)) {
return PyErr_Occurred() ? -1 : 0;
}
if (pitem) {
*pitem = next_item;
} else if (pkey && pvalue) {
if (__Pyx_unpack_tuple2(next_item, pkey, pvalue, is_dict, is_dict, 1))
return -1;
} else if (pkey) {
*pkey = next_item;
} else {
*pvalue = next_item;
}
return 1;
}
}
/////////////// pyobject_as_double.proto /////////////// /////////////// pyobject_as_double.proto ///////////////
......
...@@ -56,6 +56,15 @@ def iteritems_int(dict d): ...@@ -56,6 +56,15 @@ def iteritems_int(dict d):
[(10, 0), (11, 1), (12, 2), (13, 3)] [(10, 0), (11, 1), (12, 2), (13, 3)]
>>> iteritems_int({}) >>> iteritems_int({})
[] []
>>> iteritems_int({'a': 1})
Traceback (most recent call last):
TypeError: an integer is required
>>> iteritems_int({1: 'b'})
Traceback (most recent call last):
TypeError: an integer is required
>>> iteritems_int({'a': 'b'})
Traceback (most recent call last):
TypeError: an integer is required
""" """
cdef int k,v cdef int k,v
l = [] l = []
...@@ -113,6 +122,9 @@ def iterkeys_int(dict d): ...@@ -113,6 +122,9 @@ def iterkeys_int(dict d):
[10, 11, 12, 13] [10, 11, 12, 13]
>>> iterkeys_int({}) >>> iterkeys_int({})
[] []
>>> iterkeys_int({'a': 'b'})
Traceback (most recent call last):
TypeError: an integer is required
""" """
cdef int k cdef int k
l = [] l = []
...@@ -146,6 +158,9 @@ def iterdict_int(dict d): ...@@ -146,6 +158,9 @@ def iterdict_int(dict d):
[10, 11, 12, 13] [10, 11, 12, 13]
>>> iterdict_int({}) >>> iterdict_int({})
[] []
>>> iterdict_int({'a': 'b'})
Traceback (most recent call last):
TypeError: an integer is required
""" """
cdef int k cdef int k
l = [] l = []
...@@ -211,6 +226,9 @@ def itervalues_int(dict d): ...@@ -211,6 +226,9 @@ def itervalues_int(dict d):
[0, 1, 2, 3] [0, 1, 2, 3]
>>> itervalues_int({}) >>> itervalues_int({})
[] []
>>> itervalues_int({'a': 'b'})
Traceback (most recent call last):
TypeError: an integer is required
""" """
cdef int v cdef int v
l = [] l = []
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment