algorithms.c (KeySZSet): Represent the set as an actual (frozen) set.
[catacomb-python] / algorithms.c
index 42dbe6f..071894a 100644 (file)
@@ -86,12 +86,13 @@ PyObject *keysz_pywrap(const octet *k)
     case KSZ_SET: {
       keyszset_pyobj *o =
        PyObject_New(keyszset_pyobj, keyszset_pytype);
+      PyObject *l;
       int i, n;
       o->dfl = ARG(0);
       for (i = 0; ARG(i); i++) ;
-      n = i; o->set = PyTuple_New(n);
-      for (i = 0; i < n; i++)
-       PyTuple_SET_ITEM(o->set, i, PyInt_FromLong(ARG(i)));
+      n = i; l = PyList_New(n);
+      for (i = 0; i < n; i++) PyList_SET_ITEM(l, i, PyInt_FromLong(ARG(i)));
+      o->set = PyFrozenSet_New(l); Py_DECREF(l);
       return ((PyObject *)o);
     } break;
     default:
@@ -121,13 +122,20 @@ static PyObject *keyszrange_pynew(PyTypeObject *ty,
                                  PyObject *arg, PyObject *kw)
 {
   static const char *const kwlist[] = { "default", "min", "max", "mod", 0 };
-  int dfl, min = 0, max = 0, mod = 1;
+  int dfl, min = 0, max, mod = 1;
+  PyObject *maxobj = Py_None;
   keyszrange_pyobj *o;
 
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "i|iii:new", KWLIST,
-                                  &dfl, &min, &max, &mod))
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "i|iOi:new", KWLIST,
+                                  &dfl, &min, &maxobj, &mod))
     goto end;
-  if (dfl < 0 || min < 0) VALERR("key size cannot be negative");
+  if (maxobj == Py_None)
+    max = 0;
+  else {
+    max = PyInt_AsLong(maxobj);
+    if (max == -1 && PyErr_Occurred()) goto end;
+  }
+  if (dfl < 0 || min < 0 || max < 0) VALERR("key size cannot be negative");
   if (min > dfl || (max && dfl > max)) VALERR("bad key size bounds");
   if (mod <= 0 || dfl%mod || min%mod || max%mod)
     VALERR("bad key size modulus");
@@ -145,41 +153,30 @@ static PyObject *keyszset_pynew(PyTypeObject *ty,
                                PyObject *arg, PyObject *kw)
 {
   static const char *const kwlist[] = { "default", "set", 0 };
-  int dfl, i, n, xx;
+  int dfl, xx;
   PyObject *set = 0;
-  PyObject *x = 0, *l = 0;
+  PyObject *x = 0, *l = 0, *i = 0;
   keyszset_pyobj *o = 0;
 
   if (!PyArg_ParseTupleAndKeywords(arg, kw, "i|O:new", KWLIST, &dfl, &set))
     goto end;
-  if (!set) set = PyTuple_New(0);
-  else Py_INCREF(set);
-  if (!PySequence_Check(set)) TYERR("want a sequence");
-  n = PySequence_Size(set); if (n < 0) goto end;
+  if (set) i = PyObject_GetIter(set);
+  else { set = PyTuple_New(0); i = PyObject_GetIter(set); Py_DECREF(set); }
+  if (!i) goto end;
   l = PyList_New(0); if (!l) goto end;
   if (dfl < 0) VALERR("key size cannot be negative");
-  x = PyInt_FromLong(dfl);
-  PyList_Append(l, x);
-  Py_DECREF(x);
-  x = 0;
-  for (i = 0; i < n; i++) {
-    if ((x = PySequence_GetItem(set, i)) == 0) goto end;
-    xx = PyInt_AsLong(x);
-    if (PyErr_Occurred()) goto end;
-    if (xx == dfl) continue;
+  x = PyInt_FromLong(dfl); PyList_Append(l, x); Py_DECREF(x); x = 0;
+  for (;;) {
+    x = PyIter_Next(i); if (!x) break;
+    xx = PyInt_AsLong(x); if (xx == -1 && PyErr_Occurred()) goto end;
     if (xx < 0) VALERR("key size cannot be negative");
-    PyList_Append(l, x);
-    Py_DECREF(x);
-    x = 0;
+    PyList_Append(l, x); Py_DECREF(x); x = 0;
   }
-  Py_DECREF(set);
-  if ((set = PySequence_Tuple(l)) == 0) goto end;
+  if ((set = PyFrozenSet_New(l)) == 0) goto end;
   o = (keyszset_pyobj *)ty->tp_alloc(ty, 0);
   o->dfl = dfl;
   o->set = set;
-  Py_INCREF(set);
 end:
-  Py_XDECREF(set);
   Py_XDECREF(l);
   Py_XDECREF(x);
   return ((PyObject *)o);
@@ -187,29 +184,43 @@ end:
 
 static PyObject *kaget_min(PyObject *me, void *hunoz)
   { return (PyInt_FromLong(0)); }
-#define kaget_max kaget_min
+static PyObject *kaget_max(PyObject *me, void *hunoz)
+  { RETURN_NONE; }
+
+static PyObject *krget_max(PyObject *me, void *hunoz)
+{
+  int max = ((keyszrange_pyobj *)me)->max;
+  if (max) return (PyInt_FromLong(max));
+  else RETURN_NONE;
+}
 
 static PyObject *ksget_min(PyObject *me, void *hunoz)
 {
-  PyObject *set = ((keyszset_pyobj *)me)->set;
-  int i, n, y, x = -1;
-  n = PyTuple_GET_SIZE(set);
-  for (i = 0; i < n; i++) {
-    y = PyInt_AS_LONG(PyTuple_GET_ITEM(set, i));
+  PyObject *i = PyObject_GetIter(((keyszset_pyobj *)me)->set);
+  PyObject *v = 0;
+  int y, x = -1;
+  for (;;) {
+    v = PyIter_Next(i); if (!v) break;
+    y = PyInt_AsLong(v); assert(y >= 0);
     if (x == -1 || y < x) x = y;
   }
+  Py_DECREF(i); Py_XDECREF(v);
+  if (PyErr_Occurred()) return (0);
   return (PyInt_FromLong(x));
 }
 
 static PyObject *ksget_max(PyObject *me, void *hunoz)
 {
-  PyObject *set = ((keyszset_pyobj *)me)->set;
-  int i, n, y, x = -1;
-  n = PyTuple_GET_SIZE(set);
-  for (i = 0; i < n; i++) {
-    y = PyInt_AS_LONG(PyTuple_GET_ITEM(set, i));
+  PyObject *i = PyObject_GetIter(((keyszset_pyobj *)me)->set);
+  PyObject *v = 0;
+  int y, x = -1;
+  for (;;) {
+    v = PyIter_Next(i); if (!v) break;
+    y = PyInt_AsLong(v); assert(y >= 0);
     if (y > x) x = y;
   }
+  Py_DECREF(i); Py_XDECREF(v);
+  if (PyErr_Occurred()) return (0);
   return (PyInt_FromLong(x));
 }
 
@@ -273,13 +284,19 @@ static const PyGetSetDef keyszany_pygetset[] = {
 static const PyMemberDef keyszrange_pymembers[] = {
 #define MEMBERSTRUCT keyszrange_pyobj
   MEMBER(min,  T_INT,    READONLY, "KSZ.min -> smallest allowed key size")
-  MEMBER(max,  T_INT,    READONLY, "KSZ.max -> largest allowed key size")
   MEMBER(mod,  T_INT,    READONLY,
                            "KSZ.mod -> key size must be a multiple of this")
 #undef MEMBERSTRUCT
   { 0 }
 };
 
+static const PyGetSetDef keyszrange_pygetset[] = {
+#define GETSETNAME(op, name) kr##op##_##name
+  GET  (max,           "KSZ.max -> largest allowed key size")
+#undef GETSETNAME
+  { 0 }
+};
+
 static const PyGetSetDef keyszset_pygetset[] = {
 #define GETSETNAME(op, name) ks##op##_##name
   GET  (min,           "KSZ.min -> smallest allowed key size")
@@ -429,7 +446,7 @@ static const PyTypeObject keyszrange_pytype_skel = {
   0,                                   /* @tp_iternext@ */
   0,                                   /* @tp_methods@ */
   PYMEMBERS(keyszrange),               /* @tp_members@ */
-  0,                                   /* @tp_getset@ */
+  PYGETSET(keyszrange),                        /* @tp_getset@ */
   0,                                   /* @tp_base@ */
   0,                                   /* @tp_dict@ */
   0,                                   /* @tp_descr_get@ */
@@ -467,8 +484,8 @@ static const PyTypeObject keyszset_pytype_skel = {
     Py_TPFLAGS_BASETYPE,
 
   /* @tp_doc@ */
-  "KeySZSet(DEFAULT, SEQ)\n"
-  "  Key size constraints: size must be DEFAULT or an element of SEQ.",
+  "KeySZSet(DEFAULT, ITER)\n"
+  "  Key size constraints: size must be DEFAULT or an element of ITER.",
 
   0,                                   /* @tp_traverse@ */
   0,                                   /* @tp_clear@ */