home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 15 / AACD15.ISO / AACD / Programming / Python2 / Python20_source / Objects / rangeobject.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-25  |  4.6 KB  |  237 lines

  1.  
  2. /* Range object implementation */
  3.  
  4. #include "Python.h"
  5.  
  6. typedef struct {
  7.     PyObject_HEAD
  8.     long    start;
  9.     long    step;
  10.     long    len;
  11.     int    reps;
  12. } rangeobject;
  13.  
  14.  
  15. PyObject *
  16. PyRange_New(long start, long len, long step, int reps)
  17. {
  18.     rangeobject *obj = PyObject_NEW(rangeobject, &PyRange_Type);
  19.  
  20.     obj->start = start;
  21.     obj->len   = len;
  22.     obj->step  = step;
  23.     obj->reps  = reps;
  24.  
  25.     return (PyObject *) obj;
  26. }
  27.  
  28. static void
  29. range_dealloc(rangeobject *r)
  30. {
  31.     PyObject_DEL(r);
  32. }
  33.  
  34. static PyObject *
  35. range_item(rangeobject *r, int i)
  36. {
  37.     if (i < 0 || i >= r->len * r->reps) {
  38.         PyErr_SetString(PyExc_IndexError,
  39.                 "xrange object index out of range");
  40.         return NULL;
  41.     }
  42.  
  43.     return PyInt_FromLong(r->start + (i % r->len) * r->step);
  44. }
  45.  
  46. static int
  47. range_length(rangeobject *r)
  48. {
  49.     return r->len * r->reps;
  50. }
  51.  
  52. static PyObject *
  53. range_repr(rangeobject *r)
  54. {
  55.     /* buffers must be big enough to hold 3 longs + an int +
  56.      * a bit of "(xrange(...) * ...)" text.
  57.      */
  58.     char buf1[250];
  59.     char buf2[250];
  60.  
  61.     if (r->start == 0 && r->step == 1)
  62.         sprintf(buf1, "xrange(%ld)", r->start + r->len * r->step);
  63.  
  64.     else if (r->step == 1)
  65.         sprintf(buf1, "xrange(%ld, %ld)",
  66.             r->start,
  67.             r->start + r->len * r->step);
  68.  
  69.     else
  70.         sprintf(buf1, "xrange(%ld, %ld, %ld)",
  71.             r->start,
  72.             r->start + r->len * r->step,
  73.             r->step);
  74.  
  75.     if (r->reps != 1)
  76.         sprintf(buf2, "(%s * %d)", buf1, r->reps);
  77.  
  78.     return PyString_FromString(r->reps == 1 ? buf1 : buf2);
  79. }
  80.  
  81. static PyObject *
  82. range_concat(rangeobject *r, PyObject *obj)
  83. {
  84.     PyErr_SetString(PyExc_TypeError, "cannot concatenate xrange objects");
  85.     return NULL;
  86. }
  87.  
  88. static PyObject *
  89. range_repeat(rangeobject *r, int n)
  90. {
  91.     if (n < 0)
  92.         return (PyObject *) PyRange_New(0, 0, 1, 1);
  93.  
  94.     else if (n == 1) {
  95.         Py_INCREF(r);
  96.         return (PyObject *) r;
  97.     }
  98.  
  99.     else
  100.         return (PyObject *) PyRange_New(
  101.                         r->start,
  102.                         r->len,
  103.                         r->step,
  104.                         r->reps * n);
  105. }
  106.  
  107. static int
  108. range_compare(rangeobject *r1, rangeobject *r2)
  109. {
  110.     if (r1->start != r2->start)
  111.         return r1->start - r2->start;
  112.  
  113.     else if (r1->step != r2->step)
  114.         return r1->step - r2->step;
  115.  
  116.     else if (r1->len != r2->len)
  117.         return r1->len - r2->len;
  118.  
  119.     else
  120.         return r1->reps - r2->reps;
  121. }
  122.  
  123. static PyObject *
  124. range_slice(rangeobject *r, int low, int high)
  125. {
  126.     if (r->reps != 1) {
  127.         PyErr_SetString(PyExc_TypeError,
  128.                 "cannot slice a replicated xrange");
  129.         return NULL;
  130.     }
  131.     if (low < 0)
  132.         low = 0;
  133.     else if (low > r->len)
  134.         low = r->len;
  135.     if (high < 0)
  136.         high = 0;
  137.     if (high < low)
  138.         high = low;
  139.     else if (high > r->len)
  140.         high = r->len;
  141.  
  142.     if (low == 0 && high == r->len) {
  143.         Py_INCREF(r);
  144.         return (PyObject *) r;
  145.     }
  146.  
  147.     return (PyObject *) PyRange_New(
  148.                 low * r->step + r->start,
  149.                 high - low,
  150.                 r->step,
  151.                 1);
  152. }
  153.  
  154. static PyObject *
  155. range_tolist(rangeobject *self, PyObject *args)
  156. {
  157.     PyObject *thelist;
  158.     int j;
  159.     int len = self->len * self->reps;
  160.  
  161.     if (! PyArg_ParseTuple(args, ":tolist"))
  162.         return NULL;
  163.  
  164.     if ((thelist = PyList_New(len)) == NULL)
  165.         return NULL;
  166.  
  167.     for (j = 0; j < len; ++j)
  168.         if ((PyList_SetItem(thelist, j, (PyObject *) PyInt_FromLong(
  169.             self->start + (j % self->len) * self->step))) < 0)
  170.             return NULL;
  171.  
  172.     return thelist;
  173. }
  174.  
  175. static PyObject *
  176. range_getattr(rangeobject *r, char *name)
  177. {
  178.     static PyMethodDef range_methods[] = {
  179.         {"tolist",    (PyCFunction)range_tolist, METH_VARARGS,
  180.                  "tolist() -> list\n"
  181.                  "Return a list object with the same values."},
  182.         {NULL,        NULL}
  183.     };
  184.  
  185.     return Py_FindMethod(range_methods, (PyObject *) r, name);
  186. }
  187.  
  188. static int
  189. range_contains(rangeobject *r, PyObject *obj)
  190. {
  191.     long num = PyInt_AsLong(obj);
  192.  
  193.     if (num < 0 && PyErr_Occurred())
  194.         return -1;
  195.  
  196.     if (num < r->start || (num - r->start) % r->step)
  197.         return 0;
  198.     if (num > (r->start + (r->len * r->step)))
  199.         return 0;
  200.     return 1;
  201. }
  202.  
  203. static PySequenceMethods range_as_sequence = {
  204.     (inquiry)range_length, /*sq_length*/
  205.     (binaryfunc)range_concat, /*sq_concat*/
  206.     (intargfunc)range_repeat, /*sq_repeat*/
  207.     (intargfunc)range_item, /*sq_item*/
  208.     (intintargfunc)range_slice, /*sq_slice*/
  209.     0,        /*sq_ass_item*/
  210.     0,        /*sq_ass_slice*/
  211.     (objobjproc)range_contains, /*sq_contains*/
  212. };
  213.  
  214. PyTypeObject PyRange_Type = {
  215.     PyObject_HEAD_INIT(&PyType_Type)
  216.     0,            /* Number of items for varobject */
  217.     "xrange",        /* Name of this type */
  218.     sizeof(rangeobject),    /* Basic object size */
  219.     0,            /* Item size for varobject */
  220.     (destructor)range_dealloc, /*tp_dealloc*/
  221.     0,            /*tp_print*/
  222.     (getattrfunc)range_getattr, /*tp_getattr*/
  223.     0,            /*tp_setattr*/
  224.     (cmpfunc)range_compare, /*tp_compare*/
  225.     (reprfunc)range_repr,    /*tp_repr*/
  226.     0,            /*tp_as_number*/
  227.     &range_as_sequence,    /*tp_as_sequence*/
  228.     0,            /*tp_as_mapping*/
  229.     0,            /*tp_hash*/
  230.     0,            /*tp_call*/
  231.     0,            /*tp_str*/
  232.     0,            /*tp_getattro*/
  233.     0,            /*tp_setattro*/
  234.     0,            /*tp_as_buffer*/
  235.     Py_TPFLAGS_DEFAULT,    /*tp_flags*/
  236. };
  237.