Paul McGuire - Pastebin.com (original) (raw)

  1. 1318a1319,1507
  2. > static PyObject *
  3. > builtin_minmax(PyObject *self, PyObject *args, PyObject *kwds)
  4. > {
  5. > const char *name = "minmax";
  6. > PyObject *v, *it, *item, *val, *item2, *val2, *minitem, *minval, *maxitem, *maxval, *keyfunc=NULL;
  7. > PyObject *result = NULL;
  8. > int seqlen, cmp;
  9. >
  10. > if (PyTuple_Size(args) > 1)
  11. > v = args;
  12. > else if (!PyArg_UnpackTuple(args, (char *)name, 1, 1, &v))
  13. > return NULL;
  14. >
  15. > if (kwds != NULL && PyDict_Check(kwds) && PyDict_Size(kwds)) {
  16. > keyfunc = PyDict_GetItemString(kwds, "key");
  17. > if (PyDict_Size(kwds)!=1 || keyfunc == NULL) {
  18. > PyErr_Format(PyExc_TypeError,
  19. > "%s() got an unexpected keyword argument", name);
  20. > return NULL;
  21. > }
  22. > Py_INCREF(keyfunc);
  23. > }
  24. >
  25. > it = PyObject_GetIter(v);
  26. > if (it == NULL) {
  27. > Py_XDECREF(keyfunc);
  28. > return NULL;
  29. > }
  30. >
  31. > minitem = NULL; /* the results */
  32. > maxitem = NULL;
  33. > minval = NULL; /* the values associated with the results */
  34. > maxval = NULL;
  35. >
  36. > /* initialize min and max returns with the first item in the list */
  37. > item = PyIter_Next(it);
  38. > if (item == NULL)
  39. > {
  40. > //minitem = Py_None;
  41. > //Py_INCREF(minitem);
  42. > //maxitem = Py_None;
  43. > //Py_INCREF(maxitem);
  44. > goto EarlyExit_short_sequence;
  45. > }
  46. >
  47. > if (keyfunc != NULL) {
  48. > val = PyObject_CallFunctionObjArgs(keyfunc, item, NULL);
  49. > if (val == NULL)
  50. > goto Fail_it_item;
  51. > }
  52. > /* no key function; the value is the item */
  53. > else {
  54. > val = item;
  55. > // increment twice, as we will assign to both min and max return vals
  56. > Py_INCREF(val);
  57. > Py_INCREF(val);
  58. > }
  59. >
  60. > minitem = item;
  61. > minval = val;
  62. > maxitem = item; /* the result */
  63. > maxval = val; /* the value associated with the result */
  64. >
  65. > seqlen = PySequence_Length(v);
  66. >
  67. > // if even length sequence, put iter back at 0, to safely read by pairs
  68. > if (seqlen % 2 == 0) {
  69. > it = PyObject_GetIter(v);
  70. > }
  71. >
  72. > // read by pairs
  73. > while (( item = PyIter_Next(it) ) && (item2 = PyIter_Next(it))) {
  74. >
  75. > /* get the value from the key function */
  76. > if (keyfunc != NULL) {
  77. > val = PyObject_CallFunctionObjArgs(keyfunc, item, NULL);
  78. > val2 = PyObject_CallFunctionObjArgs(keyfunc, item2, NULL);
  79. > if (val == NULL || val2 == NULL)
  80. > goto Fail_it_item;
  81. > }
  82. > /* no key function; the value is the item */
  83. > else {
  84. > val = item;
  85. > Py_INCREF(val);
  86. > val2 = item2;
  87. > Py_INCREF(val2);
  88. > }
  89. >
  90. >
  91. > /*
  92. > if a > b:
  93. > a,b = b,a
  94. > */
  95. > cmp = PyObject_RichCompareBool(val, val2, Py_GT);
  96. > if (cmp < 0)
  97. > goto Fail_it_item_and_val;
  98. > else if (cmp > 0) {
  99. > PyObject* tmp;
  100. > tmp = val; val = val2; val2 = tmp;
  101. > tmp = item; item = item2; item2 = tmp;
  102. > }
  103. >
  104. > /*
  105. > if a < min_:
  106. > min_ = a
  107. > */
  108. > cmp = PyObject_RichCompareBool(val, minval, Py_LT);
  109. > if (cmp < 0)
  110. > goto Fail_it_item_and_val;
  111. > else if (cmp > 0) {
  112. > Py_DECREF(minval);
  113. > Py_DECREF(minitem);
  114. > minval = val;
  115. > minitem = item;
  116. > }
  117. > else {
  118. > Py_DECREF(item);
  119. > Py_DECREF(val);
  120. > }
  121. >
  122. > /*
  123. > if b > max_:
  124. > max_ = b
  125. > */
  126. > cmp = PyObject_RichCompareBool(val2, maxval, Py_GT);
  127. > if (cmp < 0)
  128. > goto Fail_it_item_and_val;
  129. > else if (cmp > 0) {
  130. > Py_DECREF(maxval);
  131. > Py_DECREF(maxitem);
  132. > maxval = val2;
  133. > maxitem = item2;
  134. > }
  135. > else {
  136. > Py_DECREF(item2);
  137. > Py_DECREF(val2);
  138. > }
  139. > }
  140. > if (PyErr_Occurred())
  141. > goto Fail_it;
  142. >
  143. > EarlyExit_short_sequence:
  144. > if (maxval == NULL) {
  145. > PyErr_Format(PyExc_ValueError,
  146. > "%s() arg is an empty sequence", name);
  147. > assert(maxitem == NULL);
  148. > }
  149. > else {
  150. > Py_DECREF(maxval);
  151. > Py_DECREF(minval);
  152. > }
  153. > Py_DECREF(it);
  154. > Py_XDECREF(keyfunc);
  155. >
  156. > if (maxitem != NULL) {
  157. > result = PyTuple_Pack(2, minitem, maxitem);
  158. > Py_DECREF(minitem);
  159. > Py_DECREF(maxitem);
  160. > }
  161. > else {
  162. > result = NULL;
  163. > }
  164. >
  165. > return result;
  166. >
  167. > Fail_it_item_and_val:
  168. > Py_DECREF(val);
  169. > Py_DECREF(val2);
  170. > Fail_it_item:
  171. > Py_DECREF(item);
  172. > Py_DECREF(item2);
  173. > Fail_it:
  174. > Py_XDECREF(minval);
  175. > Py_XDECREF(minitem);
  176. > Py_XDECREF(maxval);
  177. > Py_XDECREF(maxitem);
  178. > Py_DECREF(it);
  179. > Py_XDECREF(keyfunc);
  180. > return NULL;
  181. > }
  182. >
  183. > PyDoc_STRVAR(minmax_doc,
  184. > "minmax(iterable[, key=func]) -> value\n\
  185. > minmax(a, b, c, ...[, key=func]) -> value\n\
  186. > \n\
  187. > With a single iterable argument, return its smallest and largest items.\n\
  188. > With two or more arguments, return the smallest and largest arguments.");
  189. >
  190. >
  191. 2265a2455
  192. > {"minmax", (PyCFunction)builtin_minmax, METH_VARARGS | METH_KEYWORDS, minmax_doc},