blob: 6767feb9f2c116df6e568151c564058252c43805 [file] [log] [blame]
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001/* Drop in replacement for heapq.py
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +00002
3C implementation derived directly from heapq.py in Py2.3
4which was written by Kevin O'Connor, augmented by Tim Peters,
Éric Araujo1670b432010-09-03 22:03:10 +00005annotated by François Pinard, and converted to C by Raymond Hettinger.
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +00006
7*/
8
9#include "Python.h"
10
Georg Brandlf78e02b2008-06-10 17:40:04 +000011static int
Raymond Hettinger48f68d02014-06-14 16:43:35 -070012siftdown(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000013{
Raymond Hettinger871620d2014-05-03 18:36:48 -070014 PyObject *newitem, *parent;
Raymond Hettinger90e93382014-05-03 18:45:54 -070015 Py_ssize_t parentpos, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000016 int cmp;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000017
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000018 assert(PyList_Check(heap));
Antoine Pitrou44d52142013-03-04 20:30:01 +010019 size = PyList_GET_SIZE(heap);
20 if (pos >= size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000021 PyErr_SetString(PyExc_IndexError, "index out of range");
22 return -1;
23 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000024
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000025 /* Follow the path to the root, moving parents down until finding
26 a place newitem fits. */
Raymond Hettinger871620d2014-05-03 18:36:48 -070027 newitem = PyList_GET_ITEM(heap, pos);
Raymond Hettinger90e93382014-05-03 18:45:54 -070028 while (pos > startpos) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000029 parentpos = (pos - 1) >> 1;
30 parent = PyList_GET_ITEM(heap, parentpos);
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +000031 cmp = PyObject_RichCompareBool(newitem, parent, Py_LT);
Raymond Hettinger871620d2014-05-03 18:36:48 -070032 if (cmp == -1)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000033 return -1;
Antoine Pitrou44d52142013-03-04 20:30:01 +010034 if (size != PyList_GET_SIZE(heap)) {
Antoine Pitrou44d52142013-03-04 20:30:01 +010035 PyErr_SetString(PyExc_RuntimeError,
36 "list changed size during iteration");
37 return -1;
38 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000039 if (cmp == 0)
40 break;
Raymond Hettinger871620d2014-05-03 18:36:48 -070041 parent = PyList_GET_ITEM(heap, parentpos);
42 newitem = PyList_GET_ITEM(heap, pos);
43 PyList_SET_ITEM(heap, parentpos, newitem);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000044 PyList_SET_ITEM(heap, pos, parent);
45 pos = parentpos;
46 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000047 return 0;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000048}
49
50static int
Raymond Hettinger48f68d02014-06-14 16:43:35 -070051siftup(PyListObject *heap, Py_ssize_t pos)
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000052{
Raymond Hettingerc9926082014-05-03 15:22:07 -070053 Py_ssize_t startpos, endpos, childpos, rightpos, limit;
Raymond Hettinger871620d2014-05-03 18:36:48 -070054 PyObject *tmp1, *tmp2;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000055 int cmp;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000056
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000057 assert(PyList_Check(heap));
Raymond Hettinger871620d2014-05-03 18:36:48 -070058 endpos = PyList_GET_SIZE(heap);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000059 startpos = pos;
60 if (pos >= endpos) {
61 PyErr_SetString(PyExc_IndexError, "index out of range");
62 return -1;
63 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000064
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000065 /* Bubble up the smaller child until hitting a leaf. */
Raymond Hettingerc9926082014-05-03 15:22:07 -070066 limit = endpos / 2; /* smallest pos that has no child */
67 while (pos < limit) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000068 /* Set childpos to index of smaller child. */
Raymond Hettingerc9926082014-05-03 15:22:07 -070069 childpos = 2*pos + 1; /* leftmost child position */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000070 rightpos = childpos + 1;
71 if (rightpos < endpos) {
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +000072 cmp = PyObject_RichCompareBool(
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000073 PyList_GET_ITEM(heap, childpos),
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +000074 PyList_GET_ITEM(heap, rightpos),
75 Py_LT);
Raymond Hettinger871620d2014-05-03 18:36:48 -070076 if (cmp == -1)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000077 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000078 if (cmp == 0)
79 childpos = rightpos;
Raymond Hettinger871620d2014-05-03 18:36:48 -070080 if (endpos != PyList_GET_SIZE(heap)) {
81 PyErr_SetString(PyExc_RuntimeError,
82 "list changed size during iteration");
83 return -1;
84 }
Antoine Pitrou44d52142013-03-04 20:30:01 +010085 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000086 /* Move the smaller child up. */
Raymond Hettinger871620d2014-05-03 18:36:48 -070087 tmp1 = PyList_GET_ITEM(heap, childpos);
88 tmp2 = PyList_GET_ITEM(heap, pos);
89 PyList_SET_ITEM(heap, childpos, tmp2);
90 PyList_SET_ITEM(heap, pos, tmp1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000091 pos = childpos;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000092 }
Raymond Hettinger871620d2014-05-03 18:36:48 -070093 /* Bubble it up to its final resting place (by sifting its parents down). */
Raymond Hettinger48f68d02014-06-14 16:43:35 -070094 return siftdown(heap, startpos, pos);
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000095}
96
97static PyObject *
98heappush(PyObject *self, PyObject *args)
99{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000100 PyObject *heap, *item;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000101
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000102 if (!PyArg_UnpackTuple(args, "heappush", 2, 2, &heap, &item))
103 return NULL;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000104
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000105 if (!PyList_Check(heap)) {
106 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
107 return NULL;
108 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000109
Raymond Hettingera032e462015-05-11 10:32:57 -0700110 if (PyList_Append(heap, item))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000111 return NULL;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000112
Raymond Hettingera032e462015-05-11 10:32:57 -0700113 if (siftdown((PyListObject *)heap, 0, PyList_GET_SIZE(heap)-1))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000114 return NULL;
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700115 Py_RETURN_NONE;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000116}
117
118PyDoc_STRVAR(heappush_doc,
Raymond Hettingerbd8f2902013-01-18 17:35:25 -0800119"heappush(heap, item) -> None. Push item onto heap, maintaining the heap invariant.");
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000120
121static PyObject *
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700122heappop_internal(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000123{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000124 PyObject *lastelt, *returnitem;
125 Py_ssize_t n;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000126
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000127 if (!PyList_Check(heap)) {
128 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
129 return NULL;
130 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000131
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700132 /* raises IndexError if the heap is empty */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000133 n = PyList_GET_SIZE(heap);
134 if (n == 0) {
135 PyErr_SetString(PyExc_IndexError, "index out of range");
136 return NULL;
137 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000138
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000139 lastelt = PyList_GET_ITEM(heap, n-1) ;
140 Py_INCREF(lastelt);
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700141 if (PyList_SetSlice(heap, n-1, n, NULL)) {
Victor Stinner764a46d2013-07-17 21:50:21 +0200142 Py_DECREF(lastelt);
143 return NULL;
144 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000145 n--;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000146
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000147 if (!n)
148 return lastelt;
149 returnitem = PyList_GET_ITEM(heap, 0);
150 PyList_SET_ITEM(heap, 0, lastelt);
Raymond Hettingera032e462015-05-11 10:32:57 -0700151 if (siftup_func((PyListObject *)heap, 0)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000152 Py_DECREF(returnitem);
153 return NULL;
154 }
155 return returnitem;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000156}
157
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700158static PyObject *
159heappop(PyObject *self, PyObject *heap)
160{
161 return heappop_internal(heap, siftup);
162}
163
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000164PyDoc_STRVAR(heappop_doc,
165"Pop the smallest item off the heap, maintaining the heap invariant.");
166
167static PyObject *
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700168heapreplace_internal(PyObject *args, int siftup_func(PyListObject *, Py_ssize_t))
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000169{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000170 PyObject *heap, *item, *returnitem;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000171
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000172 if (!PyArg_UnpackTuple(args, "heapreplace", 2, 2, &heap, &item))
173 return NULL;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000174
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000175 if (!PyList_Check(heap)) {
176 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
177 return NULL;
178 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000179
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700180 if (PyList_GET_SIZE(heap) == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000181 PyErr_SetString(PyExc_IndexError, "index out of range");
182 return NULL;
183 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000184
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000185 returnitem = PyList_GET_ITEM(heap, 0);
186 Py_INCREF(item);
187 PyList_SET_ITEM(heap, 0, item);
Raymond Hettingera032e462015-05-11 10:32:57 -0700188 if (siftup_func((PyListObject *)heap, 0)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000189 Py_DECREF(returnitem);
190 return NULL;
191 }
192 return returnitem;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000193}
194
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700195static PyObject *
196heapreplace(PyObject *self, PyObject *args)
197{
198 return heapreplace_internal(args, siftup);
199}
200
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000201PyDoc_STRVAR(heapreplace_doc,
Raymond Hettingerbd8f2902013-01-18 17:35:25 -0800202"heapreplace(heap, item) -> value. Pop and return the current smallest value, and add the new item.\n\
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000203\n\
204This is more efficient than heappop() followed by heappush(), and can be\n\
205more appropriate when using a fixed-size heap. Note that the value\n\
206returned may be larger than item! That constrains reasonable uses of\n\
Raymond Hettinger8158e842004-09-06 07:04:09 +0000207this routine unless written as part of a conditional replacement:\n\n\
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000208 if item > heap[0]:\n\
209 item = heapreplace(heap, item)\n");
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000210
211static PyObject *
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000212heappushpop(PyObject *self, PyObject *args)
213{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000214 PyObject *heap, *item, *returnitem;
215 int cmp;
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000216
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000217 if (!PyArg_UnpackTuple(args, "heappushpop", 2, 2, &heap, &item))
218 return NULL;
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000219
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000220 if (!PyList_Check(heap)) {
221 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
222 return NULL;
223 }
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000224
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700225 if (PyList_GET_SIZE(heap) == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000226 Py_INCREF(item);
227 return item;
228 }
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000229
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +0000230 cmp = PyObject_RichCompareBool(PyList_GET_ITEM(heap, 0), item, Py_LT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000231 if (cmp == -1)
232 return NULL;
233 if (cmp == 0) {
234 Py_INCREF(item);
235 return item;
236 }
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000237
Raymond Hettingerb9db9e12015-05-11 19:58:56 -0700238 if (PyList_GET_SIZE(heap) == 0) {
239 PyErr_SetString(PyExc_IndexError, "index out of range");
240 return NULL;
241 }
242
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000243 returnitem = PyList_GET_ITEM(heap, 0);
244 Py_INCREF(item);
245 PyList_SET_ITEM(heap, 0, item);
Raymond Hettingera032e462015-05-11 10:32:57 -0700246 if (siftup((PyListObject *)heap, 0)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000247 Py_DECREF(returnitem);
248 return NULL;
249 }
250 return returnitem;
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000251}
252
253PyDoc_STRVAR(heappushpop_doc,
Raymond Hettingerbd8f2902013-01-18 17:35:25 -0800254"heappushpop(heap, item) -> value. Push item on the heap, then pop and return the smallest item\n\
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000255from the heap. The combined action runs more efficiently than\n\
256heappush() followed by a separate call to heappop().");
257
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700258static Py_ssize_t
259keep_top_bit(Py_ssize_t n)
260{
261 int i = 0;
262
263 while (n > 1) {
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700264 n >>= 1;
Raymond Hettingerd69755d2015-05-15 17:53:52 -0700265 i++;
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700266 }
267 return n << i;
268}
269
270/* Cache friendly version of heapify()
271 -----------------------------------
272
273 Build-up a heap in O(n) time by performing siftup() operations
274 on nodes whose children are already heaps.
275
276 The simplest way is to sift the nodes in reverse order from
277 n//2-1 to 0 inclusive. The downside is that children may be
278 out of cache by the time their parent is reached.
279
280 A better way is to not wait for the children to go out of cache.
281 Once a sibling pair of child nodes have been sifted, immediately
282 sift their parent node (while the children are still in cache).
283
284 Both ways build child heaps before their parents, so both ways
285 do the exact same number of comparisons and produce exactly
286 the same heap. The only difference is that the traversal
287 order is optimized for cache efficiency.
288*/
289
290static PyObject *
291cache_friendly_heapify(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
292{
293 Py_ssize_t i, j, m, mhalf, leftmost;
294
295 m = PyList_GET_SIZE(heap) >> 1; /* index of first childless node */
296 leftmost = keep_top_bit(m + 1) - 1; /* leftmost node in row of m */
297 mhalf = m >> 1; /* parent of first childless node */
298
299 for (i = leftmost - 1 ; i >= mhalf ; i--) {
300 j = i;
301 while (1) {
302 if (siftup_func((PyListObject *)heap, j))
303 return NULL;
304 if (!(j & 1))
305 break;
306 j >>= 1;
307 }
308 }
309
310 for (i = m - 1 ; i >= leftmost ; i--) {
311 j = i;
312 while (1) {
313 if (siftup_func((PyListObject *)heap, j))
314 return NULL;
315 if (!(j & 1))
316 break;
317 j >>= 1;
318 }
319 }
320 Py_RETURN_NONE;
321}
322
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000323static PyObject *
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700324heapify_internal(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000325{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000326 Py_ssize_t i, n;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000327
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000328 if (!PyList_Check(heap)) {
329 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
330 return NULL;
331 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000332
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700333 /* For heaps likely to be bigger than L1 cache, we use the cache
334 friendly heapify function. For smaller heaps that fit entirely
335 in cache, we prefer the simpler algorithm with less branching.
336 */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000337 n = PyList_GET_SIZE(heap);
Raymond Hettinger63648802015-05-12 21:40:50 -0700338 if (n > 2500)
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700339 return cache_friendly_heapify(heap, siftup_func);
340
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000341 /* Transform bottom-up. The largest index there's any point to
342 looking at is the largest with a child index in-range, so must
343 have 2*i + 1 < n, or i < (n-1)/2. If n is even = 2*j, this is
344 (2*j-1)/2 = j-1/2 so j-1 is the largest, which is n//2 - 1. If
345 n is odd = 2*j+1, this is (2*j+1-1)/2 = j so j-1 is the largest,
346 and that's again n//2-1.
347 */
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700348 for (i = n/2 - 1 ; i >= 0 ; i--)
349 if (siftup_func((PyListObject *)heap, i))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000350 return NULL;
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700351 Py_RETURN_NONE;
352}
353
354static PyObject *
355heapify(PyObject *self, PyObject *heap)
356{
357 return heapify_internal(heap, siftup);
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000358}
359
360PyDoc_STRVAR(heapify_doc,
361"Transform list into a heap, in-place, in O(len(heap)) time.");
362
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000363static int
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700364siftdown_max(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000365{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000366 PyObject *newitem, *parent;
Raymond Hettinger90e93382014-05-03 18:45:54 -0700367 Py_ssize_t parentpos, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000368 int cmp;
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000369
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000370 assert(PyList_Check(heap));
Raymond Hettinger90e93382014-05-03 18:45:54 -0700371 size = PyList_GET_SIZE(heap);
372 if (pos >= size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000373 PyErr_SetString(PyExc_IndexError, "index out of range");
374 return -1;
375 }
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000376
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000377 /* Follow the path to the root, moving parents down until finding
378 a place newitem fits. */
Raymond Hettinger871620d2014-05-03 18:36:48 -0700379 newitem = PyList_GET_ITEM(heap, pos);
Raymond Hettinger90e93382014-05-03 18:45:54 -0700380 while (pos > startpos) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000381 parentpos = (pos - 1) >> 1;
382 parent = PyList_GET_ITEM(heap, parentpos);
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +0000383 cmp = PyObject_RichCompareBool(parent, newitem, Py_LT);
Raymond Hettinger871620d2014-05-03 18:36:48 -0700384 if (cmp == -1)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000385 return -1;
Raymond Hettinger90e93382014-05-03 18:45:54 -0700386 if (size != PyList_GET_SIZE(heap)) {
387 PyErr_SetString(PyExc_RuntimeError,
388 "list changed size during iteration");
389 return -1;
390 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000391 if (cmp == 0)
392 break;
Raymond Hettinger871620d2014-05-03 18:36:48 -0700393 parent = PyList_GET_ITEM(heap, parentpos);
394 newitem = PyList_GET_ITEM(heap, pos);
395 PyList_SET_ITEM(heap, parentpos, newitem);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000396 PyList_SET_ITEM(heap, pos, parent);
397 pos = parentpos;
398 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000399 return 0;
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000400}
401
402static int
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700403siftup_max(PyListObject *heap, Py_ssize_t pos)
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000404{
Raymond Hettingerc9926082014-05-03 15:22:07 -0700405 Py_ssize_t startpos, endpos, childpos, rightpos, limit;
Raymond Hettinger871620d2014-05-03 18:36:48 -0700406 PyObject *tmp1, *tmp2;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000407 int cmp;
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000408
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000409 assert(PyList_Check(heap));
410 endpos = PyList_GET_SIZE(heap);
411 startpos = pos;
412 if (pos >= endpos) {
413 PyErr_SetString(PyExc_IndexError, "index out of range");
414 return -1;
415 }
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000416
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000417 /* Bubble up the smaller child until hitting a leaf. */
Raymond Hettingerc9926082014-05-03 15:22:07 -0700418 limit = endpos / 2; /* smallest pos that has no child */
419 while (pos < limit) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000420 /* Set childpos to index of smaller child. */
Raymond Hettingerc9926082014-05-03 15:22:07 -0700421 childpos = 2*pos + 1; /* leftmost child position */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000422 rightpos = childpos + 1;
423 if (rightpos < endpos) {
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +0000424 cmp = PyObject_RichCompareBool(
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000425 PyList_GET_ITEM(heap, rightpos),
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +0000426 PyList_GET_ITEM(heap, childpos),
427 Py_LT);
Raymond Hettinger871620d2014-05-03 18:36:48 -0700428 if (cmp == -1)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000429 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000430 if (cmp == 0)
431 childpos = rightpos;
Raymond Hettinger871620d2014-05-03 18:36:48 -0700432 if (endpos != PyList_GET_SIZE(heap)) {
433 PyErr_SetString(PyExc_RuntimeError,
434 "list changed size during iteration");
435 return -1;
436 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000437 }
438 /* Move the smaller child up. */
Raymond Hettinger871620d2014-05-03 18:36:48 -0700439 tmp1 = PyList_GET_ITEM(heap, childpos);
440 tmp2 = PyList_GET_ITEM(heap, pos);
441 PyList_SET_ITEM(heap, childpos, tmp2);
442 PyList_SET_ITEM(heap, pos, tmp1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000443 pos = childpos;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000444 }
Raymond Hettinger871620d2014-05-03 18:36:48 -0700445 /* Bubble it up to its final resting place (by sifting its parents down). */
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700446 return siftdown_max(heap, startpos, pos);
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000447}
448
449static PyObject *
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700450heappop_max(PyObject *self, PyObject *heap)
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000451{
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700452 return heappop_internal(heap, siftup_max);
453}
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000454
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700455PyDoc_STRVAR(heappop_max_doc, "Maxheap variant of heappop.");
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000456
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700457static PyObject *
458heapreplace_max(PyObject *self, PyObject *args)
459{
460 return heapreplace_internal(args, siftup_max);
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000461}
462
Raymond Hettinger234fb2d2014-05-11 14:21:23 -0700463PyDoc_STRVAR(heapreplace_max_doc, "Maxheap variant of heapreplace");
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000464
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700465static PyObject *
466heapify_max(PyObject *self, PyObject *heap)
467{
468 return heapify_internal(heap, siftup_max);
469}
470
471PyDoc_STRVAR(heapify_max_doc, "Maxheap variant of heapify.");
472
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000473static PyMethodDef heapq_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000474 {"heappush", (PyCFunction)heappush,
475 METH_VARARGS, heappush_doc},
476 {"heappushpop", (PyCFunction)heappushpop,
477 METH_VARARGS, heappushpop_doc},
478 {"heappop", (PyCFunction)heappop,
479 METH_O, heappop_doc},
480 {"heapreplace", (PyCFunction)heapreplace,
481 METH_VARARGS, heapreplace_doc},
482 {"heapify", (PyCFunction)heapify,
483 METH_O, heapify_doc},
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700484 {"_heappop_max", (PyCFunction)heappop_max,
485 METH_O, heappop_max_doc},
486 {"_heapreplace_max",(PyCFunction)heapreplace_max,
Raymond Hettinger234fb2d2014-05-11 14:21:23 -0700487 METH_VARARGS, heapreplace_max_doc},
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700488 {"_heapify_max", (PyCFunction)heapify_max,
489 METH_O, heapify_max_doc},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000490 {NULL, NULL} /* sentinel */
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000491};
492
493PyDoc_STRVAR(module_doc,
494"Heap queue algorithm (a.k.a. priority queue).\n\
495\n\
496Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for\n\
497all k, counting elements from 0. For the sake of comparison,\n\
498non-existing elements are considered to be infinite. The interesting\n\
499property of a heap is that a[0] is always its smallest element.\n\
500\n\
501Usage:\n\
502\n\
503heap = [] # creates an empty heap\n\
504heappush(heap, item) # pushes a new item on the heap\n\
505item = heappop(heap) # pops the smallest item from the heap\n\
506item = heap[0] # smallest item on the heap without popping it\n\
507heapify(x) # transforms list into a heap, in-place, in linear time\n\
508item = heapreplace(heap, item) # pops and returns smallest item, and adds\n\
509 # new item; the heap size is unchanged\n\
510\n\
511Our API differs from textbook heap algorithms as follows:\n\
512\n\
513- We use 0-based indexing. This makes the relationship between the\n\
514 index for a node and the indexes for its children slightly less\n\
515 obvious, but is more suitable since Python uses 0-based indexing.\n\
516\n\
517- Our heappop() method returns the smallest item, not the largest.\n\
518\n\
519These two make it possible to view the heap as a regular Python list\n\
520without surprises: heap[0] is the smallest item, and heap.sort()\n\
521maintains the heap invariant!\n");
522
523
524PyDoc_STRVAR(__about__,
525"Heap queues\n\
526\n\
Neal Norwitzc1786ea2007-08-23 23:58:43 +0000527[explanation by Fran\xc3\xa7ois Pinard]\n\
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000528\n\
529Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for\n\
530all k, counting elements from 0. For the sake of comparison,\n\
531non-existing elements are considered to be infinite. The interesting\n\
532property of a heap is that a[0] is always its smallest element.\n"
533"\n\
534The strange invariant above is meant to be an efficient memory\n\
535representation for a tournament. The numbers below are `k', not a[k]:\n\
536\n\
537 0\n\
538\n\
539 1 2\n\
540\n\
541 3 4 5 6\n\
542\n\
543 7 8 9 10 11 12 13 14\n\
544\n\
545 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30\n\
546\n\
547\n\
548In the tree above, each cell `k' is topping `2*k+1' and `2*k+2'. In\n\
549an usual binary tournament we see in sports, each cell is the winner\n\
550over the two cells it tops, and we can trace the winner down the tree\n\
551to see all opponents s/he had. However, in many computer applications\n\
552of such tournaments, we do not need to trace the history of a winner.\n\
553To be more memory efficient, when a winner is promoted, we try to\n\
554replace it by something else at a lower level, and the rule becomes\n\
555that a cell and the two cells it tops contain three different items,\n\
556but the top cell \"wins\" over the two topped cells.\n"
557"\n\
558If this heap invariant is protected at all time, index 0 is clearly\n\
559the overall winner. The simplest algorithmic way to remove it and\n\
560find the \"next\" winner is to move some loser (let's say cell 30 in the\n\
561diagram above) into the 0 position, and then percolate this new 0 down\n\
562the tree, exchanging values, until the invariant is re-established.\n\
563This is clearly logarithmic on the total number of items in the tree.\n\
564By iterating over all items, you get an O(n ln n) sort.\n"
565"\n\
566A nice feature of this sort is that you can efficiently insert new\n\
567items while the sort is going on, provided that the inserted items are\n\
568not \"better\" than the last 0'th element you extracted. This is\n\
569especially useful in simulation contexts, where the tree holds all\n\
570incoming events, and the \"win\" condition means the smallest scheduled\n\
571time. When an event schedule other events for execution, they are\n\
572scheduled into the future, so they can easily go into the heap. So, a\n\
573heap is a good structure for implementing schedulers (this is what I\n\
574used for my MIDI sequencer :-).\n"
575"\n\
576Various structures for implementing schedulers have been extensively\n\
577studied, and heaps are good for this, as they are reasonably speedy,\n\
578the speed is almost constant, and the worst case is not much different\n\
579than the average case. However, there are other representations which\n\
580are more efficient overall, yet the worst cases might be terrible.\n"
581"\n\
582Heaps are also very useful in big disk sorts. You most probably all\n\
583know that a big sort implies producing \"runs\" (which are pre-sorted\n\
584sequences, which size is usually related to the amount of CPU memory),\n\
585followed by a merging passes for these runs, which merging is often\n\
586very cleverly organised[1]. It is very important that the initial\n\
587sort produces the longest runs possible. Tournaments are a good way\n\
588to that. If, using all the memory available to hold a tournament, you\n\
589replace and percolate items that happen to fit the current run, you'll\n\
590produce runs which are twice the size of the memory for random input,\n\
591and much better for input fuzzily ordered.\n"
592"\n\
593Moreover, if you output the 0'th item on disk and get an input which\n\
594may not fit in the current tournament (because the value \"wins\" over\n\
595the last output value), it cannot fit in the heap, so the size of the\n\
596heap decreases. The freed memory could be cleverly reused immediately\n\
597for progressively building a second heap, which grows at exactly the\n\
598same rate the first heap is melting. When the first heap completely\n\
599vanishes, you switch heaps and start a new run. Clever and quite\n\
600effective!\n\
601\n\
602In a word, heaps are useful memory structures to know. I use them in\n\
603a few applications, and I think it is good to keep a `heap' module\n\
604around. :-)\n"
605"\n\
606--------------------\n\
607[1] The disk balancing algorithms which are current, nowadays, are\n\
608more annoying than clever, and this is a consequence of the seeking\n\
609capabilities of the disks. On devices which cannot seek, like big\n\
610tape drives, the story was quite different, and one had to be very\n\
611clever to ensure (far in advance) that each tape movement will be the\n\
612most effective possible (that is, will best participate at\n\
613\"progressing\" the merge). Some tapes were even able to read\n\
614backwards, and this was also used to avoid the rewinding time.\n\
615Believe me, real good tape sorts were quite spectacular to watch!\n\
616From all times, sorting has always been a Great Art! :-)\n");
617
Martin v. Löwis1a214512008-06-11 05:26:20 +0000618
619static struct PyModuleDef _heapqmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000620 PyModuleDef_HEAD_INIT,
621 "_heapq",
622 module_doc,
623 -1,
624 heapq_methods,
625 NULL,
626 NULL,
627 NULL,
628 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000629};
630
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000631PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000632PyInit__heapq(void)
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000633{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000634 PyObject *m, *about;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000635
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000636 m = PyModule_Create(&_heapqmodule);
637 if (m == NULL)
638 return NULL;
639 about = PyUnicode_DecodeUTF8(__about__, strlen(__about__), NULL);
640 PyModule_AddObject(m, "__about__", about);
641 return m;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000642}
643