]> git.proxmox.com Git - mirror_edk2.git/blame - AppPkg/Applications/Python/Python-2.7.10/Modules/_heapqmodule.c
AppPkg/Applications/Python/Python-2.7.10: Initial Checkin part 2/5.
[mirror_edk2.git] / AppPkg / Applications / Python / Python-2.7.10 / Modules / _heapqmodule.c
CommitLineData
7eb75bcc
DM
1/* Drop in replacement for heapq.py\r
2\r
3C implementation derived directly from heapq.py in Py2.3\r
4which was written by Kevin O'Connor, augmented by Tim Peters,\r
5annotated by François Pinard, and converted to C by Raymond Hettinger.\r
6\r
7*/\r
8\r
9#include "Python.h"\r
10\r
11/* Older implementations of heapq used Py_LE for comparisons. Now, it uses\r
12 Py_LT so it will match min(), sorted(), and bisect(). Unfortunately, some\r
13 client code (Twisted for example) relied on Py_LE, so this little function\r
14 restores compatibility by trying both.\r
15*/\r
16static int\r
17cmp_lt(PyObject *x, PyObject *y)\r
18{\r
19 int cmp;\r
20 static PyObject *lt = NULL;\r
21\r
22 if (lt == NULL) {\r
23 lt = PyString_FromString("__lt__");\r
24 if (lt == NULL)\r
25 return -1;\r
26 }\r
27 if (PyObject_HasAttr(x, lt))\r
28 return PyObject_RichCompareBool(x, y, Py_LT);\r
29 cmp = PyObject_RichCompareBool(y, x, Py_LE);\r
30 if (cmp != -1)\r
31 cmp = 1 - cmp;\r
32 return cmp;\r
33}\r
34\r
35static int\r
36_siftdown(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)\r
37{\r
38 PyObject *newitem, *parent;\r
39 Py_ssize_t parentpos, size;\r
40 int cmp;\r
41\r
42 assert(PyList_Check(heap));\r
43 size = PyList_GET_SIZE(heap);\r
44 if (pos >= size) {\r
45 PyErr_SetString(PyExc_IndexError, "index out of range");\r
46 return -1;\r
47 }\r
48\r
49 /* Follow the path to the root, moving parents down until finding\r
50 a place newitem fits. */\r
51 newitem = PyList_GET_ITEM(heap, pos);\r
52 while (pos > startpos) {\r
53 parentpos = (pos - 1) >> 1;\r
54 parent = PyList_GET_ITEM(heap, parentpos);\r
55 cmp = cmp_lt(newitem, parent);\r
56 if (cmp == -1)\r
57 return -1;\r
58 if (size != PyList_GET_SIZE(heap)) {\r
59 PyErr_SetString(PyExc_RuntimeError,\r
60 "list changed size during iteration");\r
61 return -1;\r
62 }\r
63 if (cmp == 0)\r
64 break;\r
65 parent = PyList_GET_ITEM(heap, parentpos);\r
66 newitem = PyList_GET_ITEM(heap, pos);\r
67 PyList_SET_ITEM(heap, parentpos, newitem);\r
68 PyList_SET_ITEM(heap, pos, parent);\r
69 pos = parentpos;\r
70 }\r
71 return 0;\r
72}\r
73\r
74static int\r
75_siftup(PyListObject *heap, Py_ssize_t pos)\r
76{\r
77 Py_ssize_t startpos, endpos, childpos, rightpos, limit;\r
78 PyObject *tmp1, *tmp2;\r
79 int cmp;\r
80\r
81 assert(PyList_Check(heap));\r
82 endpos = PyList_GET_SIZE(heap);\r
83 startpos = pos;\r
84 if (pos >= endpos) {\r
85 PyErr_SetString(PyExc_IndexError, "index out of range");\r
86 return -1;\r
87 }\r
88\r
89 /* Bubble up the smaller child until hitting a leaf. */\r
90 limit = endpos / 2; /* smallest pos that has no child */\r
91 while (pos < limit) {\r
92 /* Set childpos to index of smaller child. */\r
93 childpos = 2*pos + 1; /* leftmost child position */\r
94 rightpos = childpos + 1;\r
95 if (rightpos < endpos) {\r
96 cmp = cmp_lt(\r
97 PyList_GET_ITEM(heap, childpos),\r
98 PyList_GET_ITEM(heap, rightpos));\r
99 if (cmp == -1)\r
100 return -1;\r
101 if (cmp == 0)\r
102 childpos = rightpos;\r
103 if (endpos != PyList_GET_SIZE(heap)) {\r
104 PyErr_SetString(PyExc_RuntimeError,\r
105 "list changed size during iteration");\r
106 return -1;\r
107 }\r
108 }\r
109 /* Move the smaller child up. */\r
110 tmp1 = PyList_GET_ITEM(heap, childpos);\r
111 tmp2 = PyList_GET_ITEM(heap, pos);\r
112 PyList_SET_ITEM(heap, childpos, tmp2);\r
113 PyList_SET_ITEM(heap, pos, tmp1);\r
114 pos = childpos;\r
115 }\r
116 /* Bubble it up to its final resting place (by sifting its parents down). */\r
117 return _siftdown(heap, startpos, pos);\r
118}\r
119\r
120static PyObject *\r
121heappush(PyObject *self, PyObject *args)\r
122{\r
123 PyObject *heap, *item;\r
124\r
125 if (!PyArg_UnpackTuple(args, "heappush", 2, 2, &heap, &item))\r
126 return NULL;\r
127\r
128 if (!PyList_Check(heap)) {\r
129 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");\r
130 return NULL;\r
131 }\r
132\r
133 if (PyList_Append(heap, item) == -1)\r
134 return NULL;\r
135\r
136 if (_siftdown((PyListObject *)heap, 0, PyList_GET_SIZE(heap)-1) == -1)\r
137 return NULL;\r
138 Py_INCREF(Py_None);\r
139 return Py_None;\r
140}\r
141\r
142PyDoc_STRVAR(heappush_doc,\r
143"heappush(heap, item) -> None. Push item onto heap, maintaining the heap invariant.");\r
144\r
145static PyObject *\r
146heappop(PyObject *self, PyObject *heap)\r
147{\r
148 PyObject *lastelt, *returnitem;\r
149 Py_ssize_t n;\r
150\r
151 if (!PyList_Check(heap)) {\r
152 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");\r
153 return NULL;\r
154 }\r
155\r
156 /* # raises appropriate IndexError if heap is empty */\r
157 n = PyList_GET_SIZE(heap);\r
158 if (n == 0) {\r
159 PyErr_SetString(PyExc_IndexError, "index out of range");\r
160 return NULL;\r
161 }\r
162\r
163 lastelt = PyList_GET_ITEM(heap, n-1) ;\r
164 Py_INCREF(lastelt);\r
165 PyList_SetSlice(heap, n-1, n, NULL);\r
166 n--;\r
167\r
168 if (!n)\r
169 return lastelt;\r
170 returnitem = PyList_GET_ITEM(heap, 0);\r
171 PyList_SET_ITEM(heap, 0, lastelt);\r
172 if (_siftup((PyListObject *)heap, 0) == -1) {\r
173 Py_DECREF(returnitem);\r
174 return NULL;\r
175 }\r
176 return returnitem;\r
177}\r
178\r
179PyDoc_STRVAR(heappop_doc,\r
180"Pop the smallest item off the heap, maintaining the heap invariant.");\r
181\r
182static PyObject *\r
183heapreplace(PyObject *self, PyObject *args)\r
184{\r
185 PyObject *heap, *item, *returnitem;\r
186\r
187 if (!PyArg_UnpackTuple(args, "heapreplace", 2, 2, &heap, &item))\r
188 return NULL;\r
189\r
190 if (!PyList_Check(heap)) {\r
191 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");\r
192 return NULL;\r
193 }\r
194\r
195 if (PyList_GET_SIZE(heap) < 1) {\r
196 PyErr_SetString(PyExc_IndexError, "index out of range");\r
197 return NULL;\r
198 }\r
199\r
200 returnitem = PyList_GET_ITEM(heap, 0);\r
201 Py_INCREF(item);\r
202 PyList_SET_ITEM(heap, 0, item);\r
203 if (_siftup((PyListObject *)heap, 0) == -1) {\r
204 Py_DECREF(returnitem);\r
205 return NULL;\r
206 }\r
207 return returnitem;\r
208}\r
209\r
210PyDoc_STRVAR(heapreplace_doc,\r
211"heapreplace(heap, item) -> value. Pop and return the current smallest value, and add the new item.\n\\r
212\n\\r
213This is more efficient than heappop() followed by heappush(), and can be\n\\r
214more appropriate when using a fixed-size heap. Note that the value\n\\r
215returned may be larger than item! That constrains reasonable uses of\n\\r
216this routine unless written as part of a conditional replacement:\n\n\\r
217 if item > heap[0]:\n\\r
218 item = heapreplace(heap, item)\n");\r
219\r
220static PyObject *\r
221heappushpop(PyObject *self, PyObject *args)\r
222{\r
223 PyObject *heap, *item, *returnitem;\r
224 int cmp;\r
225\r
226 if (!PyArg_UnpackTuple(args, "heappushpop", 2, 2, &heap, &item))\r
227 return NULL;\r
228\r
229 if (!PyList_Check(heap)) {\r
230 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");\r
231 return NULL;\r
232 }\r
233\r
234 if (PyList_GET_SIZE(heap) < 1) {\r
235 Py_INCREF(item);\r
236 return item;\r
237 }\r
238\r
239 cmp = cmp_lt(PyList_GET_ITEM(heap, 0), item);\r
240 if (cmp == -1)\r
241 return NULL;\r
242 if (cmp == 0) {\r
243 Py_INCREF(item);\r
244 return item;\r
245 }\r
246\r
247 returnitem = PyList_GET_ITEM(heap, 0);\r
248 Py_INCREF(item);\r
249 PyList_SET_ITEM(heap, 0, item);\r
250 if (_siftup((PyListObject *)heap, 0) == -1) {\r
251 Py_DECREF(returnitem);\r
252 return NULL;\r
253 }\r
254 return returnitem;\r
255}\r
256\r
257PyDoc_STRVAR(heappushpop_doc,\r
258"heappushpop(heap, item) -> value. Push item on the heap, then pop and return the smallest item\n\\r
259from the heap. The combined action runs more efficiently than\n\\r
260heappush() followed by a separate call to heappop().");\r
261\r
262static PyObject *\r
263heapify(PyObject *self, PyObject *heap)\r
264{\r
265 Py_ssize_t i, n;\r
266\r
267 if (!PyList_Check(heap)) {\r
268 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");\r
269 return NULL;\r
270 }\r
271\r
272 n = PyList_GET_SIZE(heap);\r
273 /* Transform bottom-up. The largest index there's any point to\r
274 looking at is the largest with a child index in-range, so must\r
275 have 2*i + 1 < n, or i < (n-1)/2. If n is even = 2*j, this is\r
276 (2*j-1)/2 = j-1/2 so j-1 is the largest, which is n//2 - 1. If\r
277 n is odd = 2*j+1, this is (2*j+1-1)/2 = j so j-1 is the largest,\r
278 and that's again n//2-1.\r
279 */\r
280 for (i=n/2-1 ; i>=0 ; i--)\r
281 if(_siftup((PyListObject *)heap, i) == -1)\r
282 return NULL;\r
283 Py_INCREF(Py_None);\r
284 return Py_None;\r
285}\r
286\r
287PyDoc_STRVAR(heapify_doc,\r
288"Transform list into a heap, in-place, in O(len(heap)) time.");\r
289\r
290static PyObject *\r
291nlargest(PyObject *self, PyObject *args)\r
292{\r
293 PyObject *heap=NULL, *elem, *iterable, *sol, *it, *oldelem;\r
294 Py_ssize_t i, n;\r
295 int cmp;\r
296\r
297 if (!PyArg_ParseTuple(args, "nO:nlargest", &n, &iterable))\r
298 return NULL;\r
299\r
300 it = PyObject_GetIter(iterable);\r
301 if (it == NULL)\r
302 return NULL;\r
303\r
304 heap = PyList_New(0);\r
305 if (heap == NULL)\r
306 goto fail;\r
307\r
308 for (i=0 ; i<n ; i++ ){\r
309 elem = PyIter_Next(it);\r
310 if (elem == NULL) {\r
311 if (PyErr_Occurred())\r
312 goto fail;\r
313 else\r
314 goto sortit;\r
315 }\r
316 if (PyList_Append(heap, elem) == -1) {\r
317 Py_DECREF(elem);\r
318 goto fail;\r
319 }\r
320 Py_DECREF(elem);\r
321 }\r
322 if (PyList_GET_SIZE(heap) == 0)\r
323 goto sortit;\r
324\r
325 for (i=n/2-1 ; i>=0 ; i--)\r
326 if(_siftup((PyListObject *)heap, i) == -1)\r
327 goto fail;\r
328\r
329 sol = PyList_GET_ITEM(heap, 0);\r
330 while (1) {\r
331 elem = PyIter_Next(it);\r
332 if (elem == NULL) {\r
333 if (PyErr_Occurred())\r
334 goto fail;\r
335 else\r
336 goto sortit;\r
337 }\r
338 cmp = cmp_lt(sol, elem);\r
339 if (cmp == -1) {\r
340 Py_DECREF(elem);\r
341 goto fail;\r
342 }\r
343 if (cmp == 0) {\r
344 Py_DECREF(elem);\r
345 continue;\r
346 }\r
347 oldelem = PyList_GET_ITEM(heap, 0);\r
348 PyList_SET_ITEM(heap, 0, elem);\r
349 Py_DECREF(oldelem);\r
350 if (_siftup((PyListObject *)heap, 0) == -1)\r
351 goto fail;\r
352 sol = PyList_GET_ITEM(heap, 0);\r
353 }\r
354sortit:\r
355 if (PyList_Sort(heap) == -1)\r
356 goto fail;\r
357 if (PyList_Reverse(heap) == -1)\r
358 goto fail;\r
359 Py_DECREF(it);\r
360 return heap;\r
361\r
362fail:\r
363 Py_DECREF(it);\r
364 Py_XDECREF(heap);\r
365 return NULL;\r
366}\r
367\r
368PyDoc_STRVAR(nlargest_doc,\r
369"Find the n largest elements in a dataset.\n\\r
370\n\\r
371Equivalent to: sorted(iterable, reverse=True)[:n]\n");\r
372\r
373static int\r
374_siftdownmax(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)\r
375{\r
376 PyObject *newitem, *parent;\r
377 int cmp;\r
378 Py_ssize_t parentpos;\r
379\r
380 assert(PyList_Check(heap));\r
381 if (pos >= PyList_GET_SIZE(heap)) {\r
382 PyErr_SetString(PyExc_IndexError, "index out of range");\r
383 return -1;\r
384 }\r
385\r
386 newitem = PyList_GET_ITEM(heap, pos);\r
387 Py_INCREF(newitem);\r
388 /* Follow the path to the root, moving parents down until finding\r
389 a place newitem fits. */\r
390 while (pos > startpos){\r
391 parentpos = (pos - 1) >> 1;\r
392 parent = PyList_GET_ITEM(heap, parentpos);\r
393 cmp = cmp_lt(parent, newitem);\r
394 if (cmp == -1) {\r
395 Py_DECREF(newitem);\r
396 return -1;\r
397 }\r
398 if (cmp == 0)\r
399 break;\r
400 Py_INCREF(parent);\r
401 Py_DECREF(PyList_GET_ITEM(heap, pos));\r
402 PyList_SET_ITEM(heap, pos, parent);\r
403 pos = parentpos;\r
404 }\r
405 Py_DECREF(PyList_GET_ITEM(heap, pos));\r
406 PyList_SET_ITEM(heap, pos, newitem);\r
407 return 0;\r
408}\r
409\r
410static int\r
411_siftupmax(PyListObject *heap, Py_ssize_t pos)\r
412{\r
413 Py_ssize_t startpos, endpos, childpos, rightpos, limit;\r
414 int cmp;\r
415 PyObject *newitem, *tmp;\r
416\r
417 assert(PyList_Check(heap));\r
418 endpos = PyList_GET_SIZE(heap);\r
419 startpos = pos;\r
420 if (pos >= endpos) {\r
421 PyErr_SetString(PyExc_IndexError, "index out of range");\r
422 return -1;\r
423 }\r
424 newitem = PyList_GET_ITEM(heap, pos);\r
425 Py_INCREF(newitem);\r
426\r
427 /* Bubble up the smaller child until hitting a leaf. */\r
428 limit = endpos / 2; /* smallest pos that has no child */\r
429 while (pos < limit) {\r
430 /* Set childpos to index of smaller child. */\r
431 childpos = 2*pos + 1; /* leftmost child position */\r
432 rightpos = childpos + 1;\r
433 if (rightpos < endpos) {\r
434 cmp = cmp_lt(\r
435 PyList_GET_ITEM(heap, rightpos),\r
436 PyList_GET_ITEM(heap, childpos));\r
437 if (cmp == -1) {\r
438 Py_DECREF(newitem);\r
439 return -1;\r
440 }\r
441 if (cmp == 0)\r
442 childpos = rightpos;\r
443 }\r
444 /* Move the smaller child up. */\r
445 tmp = PyList_GET_ITEM(heap, childpos);\r
446 Py_INCREF(tmp);\r
447 Py_DECREF(PyList_GET_ITEM(heap, pos));\r
448 PyList_SET_ITEM(heap, pos, tmp);\r
449 pos = childpos;\r
450 }\r
451\r
452 /* The leaf at pos is empty now. Put newitem there, and bubble\r
453 it up to its final resting place (by sifting its parents down). */\r
454 Py_DECREF(PyList_GET_ITEM(heap, pos));\r
455 PyList_SET_ITEM(heap, pos, newitem);\r
456 return _siftdownmax(heap, startpos, pos);\r
457}\r
458\r
459static PyObject *\r
460nsmallest(PyObject *self, PyObject *args)\r
461{\r
462 PyObject *heap=NULL, *elem, *iterable, *los, *it, *oldelem;\r
463 Py_ssize_t i, n;\r
464 int cmp;\r
465\r
466 if (!PyArg_ParseTuple(args, "nO:nsmallest", &n, &iterable))\r
467 return NULL;\r
468\r
469 it = PyObject_GetIter(iterable);\r
470 if (it == NULL)\r
471 return NULL;\r
472\r
473 heap = PyList_New(0);\r
474 if (heap == NULL)\r
475 goto fail;\r
476\r
477 for (i=0 ; i<n ; i++ ){\r
478 elem = PyIter_Next(it);\r
479 if (elem == NULL) {\r
480 if (PyErr_Occurred())\r
481 goto fail;\r
482 else\r
483 goto sortit;\r
484 }\r
485 if (PyList_Append(heap, elem) == -1) {\r
486 Py_DECREF(elem);\r
487 goto fail;\r
488 }\r
489 Py_DECREF(elem);\r
490 }\r
491 n = PyList_GET_SIZE(heap);\r
492 if (n == 0)\r
493 goto sortit;\r
494\r
495 for (i=n/2-1 ; i>=0 ; i--)\r
496 if(_siftupmax((PyListObject *)heap, i) == -1)\r
497 goto fail;\r
498\r
499 los = PyList_GET_ITEM(heap, 0);\r
500 while (1) {\r
501 elem = PyIter_Next(it);\r
502 if (elem == NULL) {\r
503 if (PyErr_Occurred())\r
504 goto fail;\r
505 else\r
506 goto sortit;\r
507 }\r
508 cmp = cmp_lt(elem, los);\r
509 if (cmp == -1) {\r
510 Py_DECREF(elem);\r
511 goto fail;\r
512 }\r
513 if (cmp == 0) {\r
514 Py_DECREF(elem);\r
515 continue;\r
516 }\r
517\r
518 oldelem = PyList_GET_ITEM(heap, 0);\r
519 PyList_SET_ITEM(heap, 0, elem);\r
520 Py_DECREF(oldelem);\r
521 if (_siftupmax((PyListObject *)heap, 0) == -1)\r
522 goto fail;\r
523 los = PyList_GET_ITEM(heap, 0);\r
524 }\r
525\r
526sortit:\r
527 if (PyList_Sort(heap) == -1)\r
528 goto fail;\r
529 Py_DECREF(it);\r
530 return heap;\r
531\r
532fail:\r
533 Py_DECREF(it);\r
534 Py_XDECREF(heap);\r
535 return NULL;\r
536}\r
537\r
538PyDoc_STRVAR(nsmallest_doc,\r
539"Find the n smallest elements in a dataset.\n\\r
540\n\\r
541Equivalent to: sorted(iterable)[:n]\n");\r
542\r
543static PyMethodDef heapq_methods[] = {\r
544 {"heappush", (PyCFunction)heappush,\r
545 METH_VARARGS, heappush_doc},\r
546 {"heappushpop", (PyCFunction)heappushpop,\r
547 METH_VARARGS, heappushpop_doc},\r
548 {"heappop", (PyCFunction)heappop,\r
549 METH_O, heappop_doc},\r
550 {"heapreplace", (PyCFunction)heapreplace,\r
551 METH_VARARGS, heapreplace_doc},\r
552 {"heapify", (PyCFunction)heapify,\r
553 METH_O, heapify_doc},\r
554 {"nlargest", (PyCFunction)nlargest,\r
555 METH_VARARGS, nlargest_doc},\r
556 {"nsmallest", (PyCFunction)nsmallest,\r
557 METH_VARARGS, nsmallest_doc},\r
558 {NULL, NULL} /* sentinel */\r
559};\r
560\r
561PyDoc_STRVAR(module_doc,\r
562"Heap queue algorithm (a.k.a. priority queue).\n\\r
563\n\\r
564Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for\n\\r
565all k, counting elements from 0. For the sake of comparison,\n\\r
566non-existing elements are considered to be infinite. The interesting\n\\r
567property of a heap is that a[0] is always its smallest element.\n\\r
568\n\\r
569Usage:\n\\r
570\n\\r
571heap = [] # creates an empty heap\n\\r
572heappush(heap, item) # pushes a new item on the heap\n\\r
573item = heappop(heap) # pops the smallest item from the heap\n\\r
574item = heap[0] # smallest item on the heap without popping it\n\\r
575heapify(x) # transforms list into a heap, in-place, in linear time\n\\r
576item = heapreplace(heap, item) # pops and returns smallest item, and adds\n\\r
577 # new item; the heap size is unchanged\n\\r
578\n\\r
579Our API differs from textbook heap algorithms as follows:\n\\r
580\n\\r
581- We use 0-based indexing. This makes the relationship between the\n\\r
582 index for a node and the indexes for its children slightly less\n\\r
583 obvious, but is more suitable since Python uses 0-based indexing.\n\\r
584\n\\r
585- Our heappop() method returns the smallest item, not the largest.\n\\r
586\n\\r
587These two make it possible to view the heap as a regular Python list\n\\r
588without surprises: heap[0] is the smallest item, and heap.sort()\n\\r
589maintains the heap invariant!\n");\r
590\r
591\r
592PyDoc_STRVAR(__about__,\r
593"Heap queues\n\\r
594\n\\r
595