blob: d709dd44c8e371811399035a258b444ff8d6d790 [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 Hettingerc784c6d2015-05-15 21:01:13 -070053 Py_ssize_t startpos, endpos, childpos, 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 */
Raymond Hettingerc784c6d2015-05-15 21:01:13 -070070 if (childpos + 1 < endpos) {
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +000071 cmp = PyObject_RichCompareBool(
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000072 PyList_GET_ITEM(heap, childpos),
Raymond Hettingerc784c6d2015-05-15 21:01:13 -070073 PyList_GET_ITEM(heap, childpos + 1),
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +000074 Py_LT);
Raymond Hettinger871620d2014-05-03 18:36:48 -070075 if (cmp == -1)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000076 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000077 if (cmp == 0)
Raymond Hettingerc784c6d2015-05-15 21:01:13 -070078 childpos++; /* rightmost child is smallest */
Raymond Hettinger871620d2014-05-03 18:36:48 -070079 if (endpos != PyList_GET_SIZE(heap)) {
80 PyErr_SetString(PyExc_RuntimeError,
81 "list changed size during iteration");
82 return -1;
83 }
Antoine Pitrou44d52142013-03-04 20:30:01 +010084 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000085 /* Move the smaller child up. */
Raymond Hettinger871620d2014-05-03 18:36:48 -070086 tmp1 = PyList_GET_ITEM(heap, childpos);
87 tmp2 = PyList_GET_ITEM(heap, pos);
88 PyList_SET_ITEM(heap, childpos, tmp2);
89 PyList_SET_ITEM(heap, pos, tmp1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000090 pos = childpos;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000091 }
Raymond Hettinger871620d2014-05-03 18:36:48 -070092 /* Bubble it up to its final resting place (by sifting its parents down). */
Raymond Hettinger48f68d02014-06-14 16:43:35 -070093 return siftdown(heap, startpos, pos);
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000094}
95
96static PyObject *
97heappush(PyObject *self, PyObject *args)
98{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000099 PyObject *heap, *item;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000100
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000101 if (!PyArg_UnpackTuple(args, "heappush", 2, 2, &heap, &item))
102 return NULL;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000103
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000104 if (!PyList_Check(heap)) {
105 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
106 return NULL;
107 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000108
Raymond Hettingera032e462015-05-11 10:32:57 -0700109 if (PyList_Append(heap, item))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000110 return NULL;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000111
Raymond Hettingera032e462015-05-11 10:32:57 -0700112 if (siftdown((PyListObject *)heap, 0, PyList_GET_SIZE(heap)-1))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000113 return NULL;
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700114 Py_RETURN_NONE;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000115}
116
117PyDoc_STRVAR(heappush_doc,
Raymond Hettingerbd8f2902013-01-18 17:35:25 -0800118"heappush(heap, item) -> None. Push item onto heap, maintaining the heap invariant.");
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000119
120static PyObject *
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700121heappop_internal(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000122{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000123 PyObject *lastelt, *returnitem;
124 Py_ssize_t n;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000125
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000126 if (!PyList_Check(heap)) {
127 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
128 return NULL;
129 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000130
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700131 /* raises IndexError if the heap is empty */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000132 n = PyList_GET_SIZE(heap);
133 if (n == 0) {
134 PyErr_SetString(PyExc_IndexError, "index out of range");
135 return NULL;
136 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000137
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000138 lastelt = PyList_GET_ITEM(heap, n-1) ;
139 Py_INCREF(lastelt);
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700140 if (PyList_SetSlice(heap, n-1, n, NULL)) {
Victor Stinner764a46d2013-07-17 21:50:21 +0200141 Py_DECREF(lastelt);
142 return NULL;
143 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000144 n--;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000145
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000146 if (!n)
147 return lastelt;
148 returnitem = PyList_GET_ITEM(heap, 0);
149 PyList_SET_ITEM(heap, 0, lastelt);
Raymond Hettingera032e462015-05-11 10:32:57 -0700150 if (siftup_func((PyListObject *)heap, 0)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000151 Py_DECREF(returnitem);
152 return NULL;
153 }
154 return returnitem;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000155}
156
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700157static PyObject *
158heappop(PyObject *self, PyObject *heap)
159{
160 return heappop_internal(heap, siftup);
161}
162
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000163PyDoc_STRVAR(heappop_doc,
164"Pop the smallest item off the heap, maintaining the heap invariant.");
165
166static PyObject *
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700167heapreplace_internal(PyObject *args, int siftup_func(PyListObject *, Py_ssize_t))
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000168{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000169 PyObject *heap, *item, *returnitem;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000170
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000171 if (!PyArg_UnpackTuple(args, "heapreplace", 2, 2, &heap, &item))
172 return NULL;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000173
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000174 if (!PyList_Check(heap)) {
175 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
176 return NULL;
177 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000178
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700179 if (PyList_GET_SIZE(heap) == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000180 PyErr_SetString(PyExc_IndexError, "index out of range");
181 return NULL;
182 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000183
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000184 returnitem = PyList_GET_ITEM(heap, 0);
185 Py_INCREF(item);
186 PyList_SET_ITEM(heap, 0, item);
Raymond Hettingera032e462015-05-11 10:32:57 -0700187 if (siftup_func((PyListObject *)heap, 0)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000188 Py_DECREF(returnitem);
189 return NULL;
190 }
191 return returnitem;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000192}
193
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700194static PyObject *
195heapreplace(PyObject *self, PyObject *args)
196{
197 return heapreplace_internal(args, siftup);
198}
199
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000200PyDoc_STRVAR(heapreplace_doc,
Raymond Hettingerbd8f2902013-01-18 17:35:25 -0800201"heapreplace(heap, item) -> value. Pop and return the current smallest value, and add the new item.\n\
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000202\n\
203This is more efficient than heappop() followed by heappush(), and can be\n\
204more appropriate when using a fixed-size heap. Note that the value\n\
205returned may be larger than item! That constrains reasonable uses of\n\
Raymond Hettinger8158e842004-09-06 07:04:09 +0000206this routine unless written as part of a conditional replacement:\n\n\
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000207 if item > heap[0]:\n\
208 item = heapreplace(heap, item)\n");
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000209
210static PyObject *
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000211heappushpop(PyObject *self, PyObject *args)
212{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000213 PyObject *heap, *item, *returnitem;
214 int cmp;
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000215
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000216 if (!PyArg_UnpackTuple(args, "heappushpop", 2, 2, &heap, &item))
217 return NULL;
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000218
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000219 if (!PyList_Check(heap)) {
220 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
221 return NULL;
222 }
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000223
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700224 if (PyList_GET_SIZE(heap) == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000225 Py_INCREF(item);
226 return item;
227 }
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000228
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +0000229 cmp = PyObject_RichCompareBool(PyList_GET_ITEM(heap, 0), item, Py_LT);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000230 if (cmp == -1)
231 return NULL;
232 if (cmp == 0) {
233 Py_INCREF(item);
234 return item;
235 }
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000236
Raymond Hettingerb9db9e12015-05-11 19:58:56 -0700237 if (PyList_GET_SIZE(heap) == 0) {
238 PyErr_SetString(PyExc_IndexError, "index out of range");
239 return NULL;
240 }
241
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000242 returnitem = PyList_GET_ITEM(heap, 0);
243 Py_INCREF(item);
244 PyList_SET_ITEM(heap, 0, item);
Raymond Hettingera032e462015-05-11 10:32:57 -0700245 if (siftup((PyListObject *)heap, 0)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000246 Py_DECREF(returnitem);
247 return NULL;
248 }
249 return returnitem;
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000250}
251
252PyDoc_STRVAR(heappushpop_doc,
Raymond Hettingerbd8f2902013-01-18 17:35:25 -0800253"heappushpop(heap, item) -> value. Push item on the heap, then pop and return the smallest item\n\
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000254from the heap. The combined action runs more efficiently than\n\
255heappush() followed by a separate call to heappop().");
256
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700257static Py_ssize_t
258keep_top_bit(Py_ssize_t n)
259{
260 int i = 0;
261
262 while (n > 1) {
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700263 n >>= 1;
Raymond Hettingerd69755d2015-05-15 17:53:52 -0700264 i++;
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700265 }
266 return n << i;
267}
268
269/* Cache friendly version of heapify()
270 -----------------------------------
271
272 Build-up a heap in O(n) time by performing siftup() operations
273 on nodes whose children are already heaps.
274
275 The simplest way is to sift the nodes in reverse order from
276 n//2-1 to 0 inclusive. The downside is that children may be
277 out of cache by the time their parent is reached.
278
279 A better way is to not wait for the children to go out of cache.
280 Once a sibling pair of child nodes have been sifted, immediately
281 sift their parent node (while the children are still in cache).
282
283 Both ways build child heaps before their parents, so both ways
284 do the exact same number of comparisons and produce exactly
285 the same heap. The only difference is that the traversal
286 order is optimized for cache efficiency.
287*/
288
289static PyObject *
290cache_friendly_heapify(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
291{
292 Py_ssize_t i, j, m, mhalf, leftmost;
293
294 m = PyList_GET_SIZE(heap) >> 1; /* index of first childless node */
295 leftmost = keep_top_bit(m + 1) - 1; /* leftmost node in row of m */
296 mhalf = m >> 1; /* parent of first childless node */
297
298 for (i = leftmost - 1 ; i >= mhalf ; i--) {
299 j = i;
300 while (1) {
301 if (siftup_func((PyListObject *)heap, j))
302 return NULL;
303 if (!(j & 1))
304 break;
305 j >>= 1;
306 }
307 }
308
309 for (i = m - 1 ; i >= leftmost ; i--) {
310 j = i;
311 while (1) {
312 if (siftup_func((PyListObject *)heap, j))
313 return NULL;
314 if (!(j & 1))
315 break;
316 j >>= 1;
317 }
318 }
319 Py_RETURN_NONE;
320}
321
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000322static PyObject *
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700323heapify_internal(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000324{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000325 Py_ssize_t i, n;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000326
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000327 if (!PyList_Check(heap)) {
328 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
329 return NULL;
330 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000331
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700332 /* For heaps likely to be bigger than L1 cache, we use the cache
333 friendly heapify function. For smaller heaps that fit entirely
334 in cache, we prefer the simpler algorithm with less branching.
335 */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000336 n = PyList_GET_SIZE(heap);
Raymond Hettinger63648802015-05-12 21:40:50 -0700337 if (n > 2500)
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700338 return cache_friendly_heapify(heap, siftup_func);
339
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000340 /* Transform bottom-up. The largest index there's any point to
341 looking at is the largest with a child index in-range, so must
342 have 2*i + 1 < n, or i < (n-1)/2. If n is even = 2*j, this is
343 (2*j-1)/2 = j-1/2 so j-1 is the largest, which is n//2 - 1. If
344 n is odd = 2*j+1, this is (2*j+1-1)/2 = j so j-1 is the largest,
345 and that's again n//2-1.
346 */
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700347 for (i = n/2 - 1 ; i >= 0 ; i--)
348 if (siftup_func((PyListObject *)heap, i))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000349 return NULL;
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700350 Py_RETURN_NONE;
351}
352
353static PyObject *
354heapify(PyObject *self, PyObject *heap)
355{
356 return heapify_internal(heap, siftup);
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000357}
358
359PyDoc_STRVAR(heapify_doc,
360"Transform list into a heap, in-place, in O(len(heap)) time.");
361
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000362static int
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700363siftdown_max(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000364{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000365 PyObject *newitem, *parent;
Raymond Hettinger90e93382014-05-03 18:45:54 -0700366 Py_ssize_t parentpos, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000367 int cmp;
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000368
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000369 assert(PyList_Check(heap));
Raymond Hettinger90e93382014-05-03 18:45:54 -0700370 size = PyList_GET_SIZE(heap);
371 if (pos >= size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000372 PyErr_SetString(PyExc_IndexError, "index out of range");
373 return -1;
374 }
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000375
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000376 /* Follow the path to the root, moving parents down until finding
377 a place newitem fits. */
Raymond Hettinger871620d2014-05-03 18:36:48 -0700378 newitem = PyList_GET_ITEM(heap, pos);
Raymond Hettinger90e93382014-05-03 18:45:54 -0700379 while (pos > startpos) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000380 parentpos = (pos - 1) >> 1;
381 parent = PyList_GET_ITEM(heap, parentpos);
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +0000382 cmp = PyObject_RichCompareBool(parent, newitem, Py_LT);
Raymond Hettinger871620d2014-05-03 18:36:48 -0700383 if (cmp == -1)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000384 return -1;
Raymond Hettinger90e93382014-05-03 18:45:54 -0700385 if (size != PyList_GET_SIZE(heap)) {
386 PyErr_SetString(PyExc_RuntimeError,
387 "list changed size during iteration");
388 return -1;
389 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000390 if (cmp == 0)
391 break;
Raymond Hettinger871620d2014-05-03 18:36:48 -0700392 parent = PyList_GET_ITEM(heap, parentpos);
393 newitem = PyList_GET_ITEM(heap, pos);
394 PyList_SET_ITEM(heap, parentpos, newitem);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000395 PyList_SET_ITEM(heap, pos, parent);
396 pos = parentpos;
397 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000398 return 0;
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000399}
400
401static int
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700402siftup_max(PyListObject *heap, Py_ssize_t pos)
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000403{
Raymond Hettingerc784c6d2015-05-15 21:01:13 -0700404 Py_ssize_t startpos, endpos, childpos, limit;
Raymond Hettinger871620d2014-05-03 18:36:48 -0700405 PyObject *tmp1, *tmp2;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000406 int cmp;
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000407
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000408 assert(PyList_Check(heap));
409 endpos = PyList_GET_SIZE(heap);
410 startpos = pos;
411 if (pos >= endpos) {
412 PyErr_SetString(PyExc_IndexError, "index out of range");
413 return -1;
414 }
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000415
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000416 /* Bubble up the smaller child until hitting a leaf. */
Raymond Hettingerc9926082014-05-03 15:22:07 -0700417 limit = endpos / 2; /* smallest pos that has no child */
418 while (pos < limit) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000419 /* Set childpos to index of smaller child. */
Raymond Hettingerc9926082014-05-03 15:22:07 -0700420 childpos = 2*pos + 1; /* leftmost child position */
Raymond Hettingerc784c6d2015-05-15 21:01:13 -0700421 if (childpos + 1 < endpos) {
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +0000422 cmp = PyObject_RichCompareBool(
Raymond Hettingerc784c6d2015-05-15 21:01:13 -0700423 PyList_GET_ITEM(heap, childpos + 1),
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +0000424 PyList_GET_ITEM(heap, childpos),
425 Py_LT);
Raymond Hettinger871620d2014-05-03 18:36:48 -0700426 if (cmp == -1)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000427 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000428 if (cmp == 0)
Raymond Hettingerc784c6d2015-05-15 21:01:13 -0700429 childpos++; /* rightmost child is smallest */
Raymond Hettinger871620d2014-05-03 18:36:48 -0700430 if (endpos != PyList_GET_SIZE(heap)) {
431 PyErr_SetString(PyExc_RuntimeError,
432 "list changed size during iteration");
433 return -1;
434 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000435 }
436 /* Move the smaller child up. */
Raymond Hettinger871620d2014-05-03 18:36:48 -0700437 tmp1 = PyList_GET_ITEM(heap, childpos);
438 tmp2 = PyList_GET_ITEM(heap, pos);
439 PyList_SET_ITEM(heap, childpos, tmp2);
440 PyList_SET_ITEM(heap, pos, tmp1);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000441 pos = childpos;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000442 }
Raymond Hettinger871620d2014-05-03 18:36:48 -0700443 /* Bubble it up to its final resting place (by sifting its parents down). */
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700444 return siftdown_max(heap, startpos, pos);
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000445}
446
447static PyObject *
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700448heappop_max(PyObject *self, PyObject *heap)
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000449{
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700450 return heappop_internal(heap, siftup_max);
451}
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000452
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700453PyDoc_STRVAR(heappop_max_doc, "Maxheap variant of heappop.");
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000454
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700455static PyObject *
456heapreplace_max(PyObject *self, PyObject *args)
457{
458 return heapreplace_internal(args, siftup_max);
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000459}
460
Raymond Hettinger234fb2d2014-05-11 14:21:23 -0700461PyDoc_STRVAR(heapreplace_max_doc, "Maxheap variant of heapreplace");
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000462
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700463static PyObject *
464heapify_max(PyObject *self, PyObject *heap)
465{
466 return heapify_internal(heap, siftup_max);
467}
468
469PyDoc_STRVAR(heapify_max_doc, "Maxheap variant of heapify.");
470
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000471static PyMethodDef heapq_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000472 {"heappush", (PyCFunction)heappush,
473 METH_VARARGS, heappush_doc},
474 {"heappushpop", (PyCFunction)heappushpop,
475 METH_VARARGS, heappushpop_doc},
476 {"heappop", (PyCFunction)heappop,
477 METH_O, heappop_doc},
478 {"heapreplace", (PyCFunction)heapreplace,
479 METH_VARARGS, heapreplace_doc},
480 {"heapify", (PyCFunction)heapify,
481 METH_O, heapify_doc},
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700482 {"_heappop_max", (PyCFunction)heappop_max,
483 METH_O, heappop_max_doc},
484 {"_heapreplace_max",(PyCFunction)heapreplace_max,
Raymond Hettinger234fb2d2014-05-11 14:21:23 -0700485 METH_VARARGS, heapreplace_max_doc},
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700486 {"_heapify_max", (PyCFunction)heapify_max,
487 METH_O, heapify_max_doc},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000488 {NULL, NULL} /* sentinel */
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000489};
490
491PyDoc_STRVAR(module_doc,
492"Heap queue algorithm (a.k.a. priority queue).\n\
493\n\
494Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for\n\
495all k, counting elements from 0. For the sake of comparison,\n\
496non-existing elements are considered to be infinite. The interesting\n\
497property of a heap is that a[0] is always its smallest element.\n\
498\n\
499Usage:\n\
500\n\
501heap = [] # creates an empty heap\n\
502heappush(heap, item) # pushes a new item on the heap\n\
503item = heappop(heap) # pops the smallest item from the heap\n\
504item = heap[0] # smallest item on the heap without popping it\n\
505heapify(x) # transforms list into a heap, in-place, in linear time\n\
506item = heapreplace(heap, item) # pops and returns smallest item, and adds\n\
507 # new item; the heap size is unchanged\n\
508\n\
509Our API differs from textbook heap algorithms as follows:\n\
510\n\
511- We use 0-based indexing. This makes the relationship between the\n\
512 index for a node and the indexes for its children slightly less\n\
513 obvious, but is more suitable since Python uses 0-based indexing.\n\
514\n\
515- Our heappop() method returns the smallest item, not the largest.\n\
516\n\
517These two make it possible to view the heap as a regular Python list\n\
518without surprises: heap[0] is the smallest item, and heap.sort()\n\
519maintains the heap invariant!\n");
520
521
522PyDoc_STRVAR(__about__,
523"Heap queues\n\
524\n\
Neal Norwitzc1786ea2007-08-23 23:58:43 +0000525[explanation by Fran\xc3\xa7ois Pinard]\n\
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000526\n\
527Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for\n\
528all k, counting elements from 0. For the sake of comparison,\n\
529non-existing elements are considered to be infinite. The interesting\n\
530property of a heap is that a[0] is always its smallest element.\n"
531"\n\
532The strange invariant above is meant to be an efficient memory\n\
533representation for a tournament. The numbers below are `k', not a[k]:\n\
534\n\
535 0\n\
536\n\
537 1 2\n\
538\n\
539 3 4 5 6\n\
540\n\
541 7 8 9 10 11 12 13 14\n\
542\n\
543 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30\n\
544\n\
545\n\
546In the tree above, each cell `k' is topping `2*k+1' and `2*k+2'. In\n\
547an usual binary tournament we see in sports, each cell is the winner\n\
548over the two cells it tops, and we can trace the winner down the tree\n\
549to see all opponents s/he had. However, in many computer applications\n\
550of such tournaments, we do not need to trace the history of a winner.\n\
551To be more memory efficient, when a winner is promoted, we try to\n\
552replace it by something else at a lower level, and the rule becomes\n\
553that a cell and the two cells it tops contain three different items,\n\
554but the top cell \"wins\" over the two topped cells.\n"
555"\n\
556If this heap invariant is protected at all time, index 0 is clearly\n\
557the overall winner. The simplest algorithmic way to remove it and\n\
558find the \"next\" winner is to move some loser (let's say cell 30 in the\n\
559diagram above) into the 0 position, and then percolate this new 0 down\n\
560the tree, exchanging values, until the invariant is re-established.\n\
561This is clearly logarithmic on the total number of items in the tree.\n\
562By iterating over all items, you get an O(n ln n) sort.\n"
563"\n\
564A nice feature of this sort is that you can efficiently insert new\n\
565items while the sort is going on, provided that the inserted items are\n\
566not \"better\" than the last 0'th element you extracted. This is\n\
567especially useful in simulation contexts, where the tree holds all\n\
568incoming events, and the \"win\" condition means the smallest scheduled\n\
569time. When an event schedule other events for execution, they are\n\
570scheduled into the future, so they can easily go into the heap. So, a\n\
571heap is a good structure for implementing schedulers (this is what I\n\
572used for my MIDI sequencer :-).\n"
573"\n\
574Various structures for implementing schedulers have been extensively\n\
575studied, and heaps are good for this, as they are reasonably speedy,\n\
576the speed is almost constant, and the worst case is not much different\n\
577than the average case. However, there are other representations which\n\
578are more efficient overall, yet the worst cases might be terrible.\n"
579"\n\
580Heaps are also very useful in big disk sorts. You most probably all\n\
581know that a big sort implies producing \"runs\" (which are pre-sorted\n\
582sequences, which size is usually related to the amount of CPU memory),\n\
583followed by a merging passes for these runs, which merging is often\n\
584very cleverly organised[1]. It is very important that the initial\n\
585sort produces the longest runs possible. Tournaments are a good way\n\
586to that. If, using all the memory available to hold a tournament, you\n\
587replace and percolate items that happen to fit the current run, you'll\n\
588produce runs which are twice the size of the memory for random input,\n\
589and much better for input fuzzily ordered.\n"
590"\n\
591Moreover, if you output the 0'th item on disk and get an input which\n\
592may not fit in the current tournament (because the value \"wins\" over\n\
593the last output value), it cannot fit in the heap, so the size of the\n\
594heap decreases. The freed memory could be cleverly reused immediately\n\
595for progressively building a second heap, which grows at exactly the\n\
596same rate the first heap is melting. When the first heap completely\n\
597vanishes, you switch heaps and start a new run. Clever and quite\n\
598effective!\n\
599\n\
600In a word, heaps are useful memory structures to know. I use them in\n\
601a few applications, and I think it is good to keep a `heap' module\n\
602around. :-)\n"
603"\n\
604--------------------\n\
605[1] The disk balancing algorithms which are current, nowadays, are\n\
606more annoying than clever, and this is a consequence of the seeking\n\
607capabilities of the disks. On devices which cannot seek, like big\n\
608tape drives, the story was quite different, and one had to be very\n\
609clever to ensure (far in advance) that each tape movement will be the\n\
610most effective possible (that is, will best participate at\n\
611\"progressing\" the merge). Some tapes were even able to read\n\
612backwards, and this was also used to avoid the rewinding time.\n\
613Believe me, real good tape sorts were quite spectacular to watch!\n\
614From all times, sorting has always been a Great Art! :-)\n");
615
Martin v. Löwis1a214512008-06-11 05:26:20 +0000616
617static struct PyModuleDef _heapqmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000618 PyModuleDef_HEAD_INIT,
619 "_heapq",
620 module_doc,
621 -1,
622 heapq_methods,
623 NULL,
624 NULL,
625 NULL,
626 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000627};
628
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000629PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000630PyInit__heapq(void)
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000631{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000632 PyObject *m, *about;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000633
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000634 m = PyModule_Create(&_heapqmodule);
635 if (m == NULL)
636 return NULL;
637 about = PyUnicode_DecodeUTF8(__about__, strlen(__about__), NULL);
638 PyModule_AddObject(m, "__about__", about);
639 return m;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000640}
641