1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
#include "piterobject.h"
#if HAVE_GENERATORS
DEFINEFN vinfo_t* PsycoSeqIter_NEW(PsycoObject* po, vinfo_t* seq)
{
vinfo_t* zero;
vinfo_t* result = vinfo_new(VirtualTime_New(&psyco_computed_seqiter));
result->array = array_new(SEQITER_TOTAL);
result->array->items[iOB_TYPE] =
vinfo_new(CompileTime_New((long)(&PySeqIter_Type)));
/* the iterator index is immediately run-time because it is
very likely to be unpromoted to run-time anyway */
zero = psyco_vi_Zero();
result->array->items[iSEQITER_IT_INDEX] = make_runtime_copy(po, zero);
vinfo_decref(zero, po);
/*result->array->items[SEQITER_IT_INDEX] =
vinfo_new(CompileTime_New(0));*/
result->array->items[iSEQITER_IT_SEQ] = seq;
return result;
}
static vinfo_t* piter_getiter(PsycoObject* po, vinfo_t* v)
{
vinfo_incref(v);
return v;
}
static vinfo_t* piter_next(PsycoObject* po, vinfo_t* v)
{
vinfo_t* seq;
vinfo_t* index;
vinfo_t* result;
seq = psyco_get_const(po, v, SEQITER_it_seq);
if (seq == NULL)
return NULL;
index = psyco_get_field(po, v, SEQITER_it_index);
if (index == NULL)
return NULL;
result = PsycoSequence_GetItem(po, seq, index);
if (result == NULL) {
vinfo_t* matches = PycException_Matches(po, PyExc_IndexError);
if (runtime_NON_NULL_t(po, matches) == true) {
PycException_SetVInfo(po, PyExc_StopIteration,
psyco_vi_None());
}
}
else {
/* very remotely potential incompatibility: when exhausted,
the internal iterator index is not incremented. Python
is not consistent in this respect. This could be an
issue if an iterator of a mutable object is not
immediately deleted when exhausted. Well, I guess that
muting an object we iterate over is generally considered
as DDIWWY (Don't Do It -- We Warned You.) */
vinfo_t* index_plus_1 = integer_add_i(po, index, 1, true);
if (index_plus_1 == NULL ||
!psyco_put_field(po, v, SEQITER_it_index, index_plus_1)) {
vinfo_decref(result, po);
result = NULL;
}
vinfo_xdecref(index_plus_1, po);
}
vinfo_decref(index, po);
return result;
}
static bool compute_seqiter(PsycoObject* po, vinfo_t* v)
{
vinfo_t* seq;
vinfo_t* index;
vinfo_t* newobj;
index = vinfo_getitem(v, iSEQITER_IT_INDEX);
if (index == NULL)
return false;
seq = vinfo_getitem(v, iSEQITER_IT_SEQ);
if (seq == NULL)
return false;
newobj = psyco_generic_call(po, PySeqIter_New,
CfReturnRef|CfPyErrIfNull, "v", seq);
if (newobj == NULL)
return false;
/* Put the current index into the seq iterator.
This is done by putting the value directly in the
seqiterobject structure; it could be done by calling
PyIter_Next() n times but obviously that's not too
good a solution */
if (!psyco_knowntobe(index, 0)) {
if (!psyco_put_field(po, v, SEQITER_it_index, index)) {
vinfo_decref(newobj, po);
return false;
}
}
/* Remove the SEQITER_IT_INDEX entry from v->array because it
is a mutable field now, and could be changed at any time by
anybody .*/
psyco_forget_field(po, v, SEQITER_it_index);
vinfo_move(po, v, newobj);
return true;
}
DEFINEVAR source_virtual_t psyco_computed_seqiter;
INITIALIZATIONFN
void psy_iterobject_init(void)
{
Psyco_DefineMeta(PySeqIter_Type.tp_iter, &piter_getiter);
Psyco_DefineMeta(PySeqIter_Type.tp_iternext, &piter_next);
/* iterator object are mutable;
they must be forced out of virtual-time across function calls */
INIT_SVIRTUAL_NOCALL(psyco_computed_seqiter, compute_seqiter, 1);
}
#else /* !HAVE_GENERATORS */
INITIALIZATIONFN
void psy_iterobject_init(void)
{
}
#endif /* HAVE_GENERATORS */
|