blob: 6bc18b5f82fb82db52cec8b6a90256db928196b9 [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
Pablo Galindoe2f48bf2018-09-28 20:39:43 +010011#include "clinic/_heapqmodule.c.h"
12
13/*[clinic input]
14module _heapq
15[clinic start generated code]*/
16/*[clinic end generated code: output=da39a3ee5e6b4b0d input=d7cca0a2e4c0ceb3]*/
17
Georg Brandlf78e02b2008-06-10 17:40:04 +000018static int
Raymond Hettinger48f68d02014-06-14 16:43:35 -070019siftdown(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000020{
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070021 PyObject *newitem, *parent, **arr;
Raymond Hettinger90e93382014-05-03 18:45:54 -070022 Py_ssize_t parentpos, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000023 int cmp;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000024
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000025 assert(PyList_Check(heap));
Antoine Pitrou44d52142013-03-04 20:30:01 +010026 size = PyList_GET_SIZE(heap);
27 if (pos >= size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000028 PyErr_SetString(PyExc_IndexError, "index out of range");
29 return -1;
30 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000031
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000032 /* Follow the path to the root, moving parents down until finding
33 a place newitem fits. */
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070034 arr = _PyList_ITEMS(heap);
35 newitem = arr[pos];
Raymond Hettinger90e93382014-05-03 18:45:54 -070036 while (pos > startpos) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000037 parentpos = (pos - 1) >> 1;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070038 parent = arr[parentpos];
Pablo Galindo79f89e62020-01-23 14:07:05 +000039 Py_INCREF(newitem);
40 Py_INCREF(parent);
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +000041 cmp = PyObject_RichCompareBool(newitem, parent, Py_LT);
Pablo Galindo79f89e62020-01-23 14:07:05 +000042 Py_DECREF(parent);
43 Py_DECREF(newitem);
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070044 if (cmp < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000045 return -1;
Antoine Pitrou44d52142013-03-04 20:30:01 +010046 if (size != PyList_GET_SIZE(heap)) {
Antoine Pitrou44d52142013-03-04 20:30:01 +010047 PyErr_SetString(PyExc_RuntimeError,
48 "list changed size during iteration");
49 return -1;
50 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000051 if (cmp == 0)
52 break;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070053 arr = _PyList_ITEMS(heap);
54 parent = arr[parentpos];
55 newitem = arr[pos];
56 arr[parentpos] = newitem;
57 arr[pos] = parent;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000058 pos = parentpos;
59 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000060 return 0;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000061}
62
63static int
Raymond Hettinger48f68d02014-06-14 16:43:35 -070064siftup(PyListObject *heap, Py_ssize_t pos)
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000065{
Raymond Hettingerc784c6d2015-05-15 21:01:13 -070066 Py_ssize_t startpos, endpos, childpos, limit;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070067 PyObject *tmp1, *tmp2, **arr;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000068 int cmp;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000069
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000070 assert(PyList_Check(heap));
Raymond Hettinger871620d2014-05-03 18:36:48 -070071 endpos = PyList_GET_SIZE(heap);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000072 startpos = pos;
73 if (pos >= endpos) {
74 PyErr_SetString(PyExc_IndexError, "index out of range");
75 return -1;
76 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000077
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000078 /* Bubble up the smaller child until hitting a leaf. */
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070079 arr = _PyList_ITEMS(heap);
Raymond Hettingercfe5b6c2015-07-20 00:25:50 -040080 limit = endpos >> 1; /* smallest pos that has no child */
Raymond Hettingerc9926082014-05-03 15:22:07 -070081 while (pos < limit) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000082 /* Set childpos to index of smaller child. */
Raymond Hettingerc9926082014-05-03 15:22:07 -070083 childpos = 2*pos + 1; /* leftmost child position */
Raymond Hettingerc784c6d2015-05-15 21:01:13 -070084 if (childpos + 1 < endpos) {
Pablo Galindo79f89e62020-01-23 14:07:05 +000085 PyObject* a = arr[childpos];
86 PyObject* b = arr[childpos + 1];
87 Py_INCREF(a);
88 Py_INCREF(b);
89 cmp = PyObject_RichCompareBool(a, b, Py_LT);
90 Py_DECREF(a);
91 Py_DECREF(b);
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070092 if (cmp < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000093 return -1;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070094 childpos += ((unsigned)cmp ^ 1); /* increment when cmp==0 */
Raymond Hettinger2300bf22015-12-07 20:45:16 -080095 arr = _PyList_ITEMS(heap); /* arr may have changed */
Raymond Hettinger871620d2014-05-03 18:36:48 -070096 if (endpos != PyList_GET_SIZE(heap)) {
97 PyErr_SetString(PyExc_RuntimeError,
98 "list changed size during iteration");
99 return -1;
100 }
Antoine Pitrou44d52142013-03-04 20:30:01 +0100101 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000102 /* Move the smaller child up. */
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700103 tmp1 = arr[childpos];
104 tmp2 = arr[pos];
105 arr[childpos] = tmp2;
106 arr[pos] = tmp1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000107 pos = childpos;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000108 }
Raymond Hettinger871620d2014-05-03 18:36:48 -0700109 /* Bubble it up to its final resting place (by sifting its parents down). */
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700110 return siftdown(heap, startpos, pos);
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000111}
112
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100113/*[clinic input]
114_heapq.heappush
115
116 heap: object
117 item: object
118 /
119
120Push item onto heap, maintaining the heap invariant.
121[clinic start generated code]*/
122
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000123static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100124_heapq_heappush_impl(PyObject *module, PyObject *heap, PyObject *item)
125/*[clinic end generated code: output=912c094f47663935 input=7913545cb5118842]*/
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 Hettingera032e462015-05-11 10:32:57 -0700132 if (PyList_Append(heap, item))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000133 return NULL;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000134
Raymond Hettingera032e462015-05-11 10:32:57 -0700135 if (siftdown((PyListObject *)heap, 0, PyList_GET_SIZE(heap)-1))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000136 return NULL;
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700137 Py_RETURN_NONE;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000138}
139
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000140static PyObject *
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700141heappop_internal(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000142{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000143 PyObject *lastelt, *returnitem;
144 Py_ssize_t n;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000145
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000146 if (!PyList_Check(heap)) {
147 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
148 return NULL;
149 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000150
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700151 /* raises IndexError if the heap is empty */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000152 n = PyList_GET_SIZE(heap);
153 if (n == 0) {
154 PyErr_SetString(PyExc_IndexError, "index out of range");
155 return NULL;
156 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000157
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000158 lastelt = PyList_GET_ITEM(heap, n-1) ;
159 Py_INCREF(lastelt);
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700160 if (PyList_SetSlice(heap, n-1, n, NULL)) {
Victor Stinner764a46d2013-07-17 21:50:21 +0200161 Py_DECREF(lastelt);
162 return NULL;
163 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000164 n--;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000165
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000166 if (!n)
167 return lastelt;
168 returnitem = PyList_GET_ITEM(heap, 0);
169 PyList_SET_ITEM(heap, 0, lastelt);
Raymond Hettingera032e462015-05-11 10:32:57 -0700170 if (siftup_func((PyListObject *)heap, 0)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000171 Py_DECREF(returnitem);
172 return NULL;
173 }
174 return returnitem;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000175}
176
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100177/*[clinic input]
178_heapq.heappop
179
180 heap: object
181 /
182
183Pop the smallest item off the heap, maintaining the heap invariant.
184[clinic start generated code]*/
185
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700186static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100187_heapq_heappop(PyObject *module, PyObject *heap)
188/*[clinic end generated code: output=e1bbbc9866bce179 input=9bd36317b806033d]*/
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700189{
190 return heappop_internal(heap, siftup);
191}
192
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000193static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100194heapreplace_internal(PyObject *heap, PyObject *item, int siftup_func(PyListObject *, Py_ssize_t))
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000195{
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100196 PyObject *returnitem;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000197
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000198 if (!PyList_Check(heap)) {
199 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
200 return NULL;
201 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000202
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700203 if (PyList_GET_SIZE(heap) == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000204 PyErr_SetString(PyExc_IndexError, "index out of range");
205 return NULL;
206 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000207
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000208 returnitem = PyList_GET_ITEM(heap, 0);
209 Py_INCREF(item);
210 PyList_SET_ITEM(heap, 0, item);
Raymond Hettingera032e462015-05-11 10:32:57 -0700211 if (siftup_func((PyListObject *)heap, 0)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000212 Py_DECREF(returnitem);
213 return NULL;
214 }
215 return returnitem;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000216}
217
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100218
219/*[clinic input]
220_heapq.heapreplace
221
222 heap: object
223 item: object
224 /
225
226Pop and return the current smallest value, and add the new item.
227
228This is more efficient than heappop() followed by heappush(), and can be
229more appropriate when using a fixed-size heap. Note that the value
230returned may be larger than item! That constrains reasonable uses of
231this routine unless written as part of a conditional replacement:
232
233 if item > heap[0]:
234 item = heapreplace(heap, item)
235[clinic start generated code]*/
236
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700237static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100238_heapq_heapreplace_impl(PyObject *module, PyObject *heap, PyObject *item)
239/*[clinic end generated code: output=82ea55be8fbe24b4 input=e57ae8f4ecfc88e3]*/
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700240{
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100241 return heapreplace_internal(heap, item, siftup);
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700242}
243
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100244/*[clinic input]
245_heapq.heappushpop
246
247 heap: object
248 item: object
249 /
250
251Push item on the heap, then pop and return the smallest item from the heap.
252
253The combined action runs more efficiently than heappush() followed by
254a separate call to heappop().
255[clinic start generated code]*/
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000256
257static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100258_heapq_heappushpop_impl(PyObject *module, PyObject *heap, PyObject *item)
259/*[clinic end generated code: output=67231dc98ed5774f input=eb48c90ba77b2214]*/
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000260{
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100261 PyObject *returnitem;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000262 int cmp;
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000263
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000264 if (!PyList_Check(heap)) {
265 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
266 return NULL;
267 }
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000268
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700269 if (PyList_GET_SIZE(heap) == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000270 Py_INCREF(item);
271 return item;
272 }
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000273
Pablo Galindo79f89e62020-01-23 14:07:05 +0000274 PyObject* top = PyList_GET_ITEM(heap, 0);
275 Py_INCREF(top);
276 cmp = PyObject_RichCompareBool(top, item, Py_LT);
277 Py_DECREF(top);
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700278 if (cmp < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000279 return NULL;
280 if (cmp == 0) {
281 Py_INCREF(item);
282 return item;
283 }
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000284
Raymond Hettingerb9db9e12015-05-11 19:58:56 -0700285 if (PyList_GET_SIZE(heap) == 0) {
286 PyErr_SetString(PyExc_IndexError, "index out of range");
287 return NULL;
288 }
289
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000290 returnitem = PyList_GET_ITEM(heap, 0);
291 Py_INCREF(item);
292 PyList_SET_ITEM(heap, 0, item);
Raymond Hettingera032e462015-05-11 10:32:57 -0700293 if (siftup((PyListObject *)heap, 0)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000294 Py_DECREF(returnitem);
295 return NULL;
296 }
297 return returnitem;
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000298}
299
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700300static Py_ssize_t
301keep_top_bit(Py_ssize_t n)
302{
303 int i = 0;
304
305 while (n > 1) {
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700306 n >>= 1;
Raymond Hettingerd69755d2015-05-15 17:53:52 -0700307 i++;
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700308 }
309 return n << i;
310}
311
312/* Cache friendly version of heapify()
313 -----------------------------------
314
315 Build-up a heap in O(n) time by performing siftup() operations
316 on nodes whose children are already heaps.
317
318 The simplest way is to sift the nodes in reverse order from
319 n//2-1 to 0 inclusive. The downside is that children may be
320 out of cache by the time their parent is reached.
321
322 A better way is to not wait for the children to go out of cache.
323 Once a sibling pair of child nodes have been sifted, immediately
324 sift their parent node (while the children are still in cache).
325
326 Both ways build child heaps before their parents, so both ways
327 do the exact same number of comparisons and produce exactly
328 the same heap. The only difference is that the traversal
329 order is optimized for cache efficiency.
330*/
331
332static PyObject *
333cache_friendly_heapify(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
334{
335 Py_ssize_t i, j, m, mhalf, leftmost;
336
337 m = PyList_GET_SIZE(heap) >> 1; /* index of first childless node */
338 leftmost = keep_top_bit(m + 1) - 1; /* leftmost node in row of m */
339 mhalf = m >> 1; /* parent of first childless node */
340
341 for (i = leftmost - 1 ; i >= mhalf ; i--) {
342 j = i;
343 while (1) {
344 if (siftup_func((PyListObject *)heap, j))
345 return NULL;
346 if (!(j & 1))
347 break;
348 j >>= 1;
349 }
350 }
351
352 for (i = m - 1 ; i >= leftmost ; i--) {
353 j = i;
354 while (1) {
355 if (siftup_func((PyListObject *)heap, j))
356 return NULL;
357 if (!(j & 1))
358 break;
359 j >>= 1;
360 }
361 }
362 Py_RETURN_NONE;
363}
364
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000365static PyObject *
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700366heapify_internal(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000367{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000368 Py_ssize_t i, n;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000369
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000370 if (!PyList_Check(heap)) {
371 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
372 return NULL;
373 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000374
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700375 /* For heaps likely to be bigger than L1 cache, we use the cache
376 friendly heapify function. For smaller heaps that fit entirely
377 in cache, we prefer the simpler algorithm with less branching.
378 */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000379 n = PyList_GET_SIZE(heap);
Raymond Hettinger63648802015-05-12 21:40:50 -0700380 if (n > 2500)
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700381 return cache_friendly_heapify(heap, siftup_func);
382
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000383 /* Transform bottom-up. The largest index there's any point to
384 looking at is the largest with a child index in-range, so must
385 have 2*i + 1 < n, or i < (n-1)/2. If n is even = 2*j, this is
386 (2*j-1)/2 = j-1/2 so j-1 is the largest, which is n//2 - 1. If
387 n is odd = 2*j+1, this is (2*j+1-1)/2 = j so j-1 is the largest,
388 and that's again n//2-1.
389 */
Raymond Hettingercfe5b6c2015-07-20 00:25:50 -0400390 for (i = (n >> 1) - 1 ; i >= 0 ; i--)
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700391 if (siftup_func((PyListObject *)heap, i))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000392 return NULL;
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700393 Py_RETURN_NONE;
394}
395
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100396/*[clinic input]
397_heapq.heapify
398
399 heap: object
400 /
401
402Transform list into a heap, in-place, in O(len(heap)) time.
403[clinic start generated code]*/
404
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700405static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100406_heapq_heapify(PyObject *module, PyObject *heap)
407/*[clinic end generated code: output=11483f23627c4616 input=872c87504b8de970]*/
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700408{
409 return heapify_internal(heap, siftup);
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000410}
411
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000412static int
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700413siftdown_max(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000414{
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700415 PyObject *newitem, *parent, **arr;
Raymond Hettinger90e93382014-05-03 18:45:54 -0700416 Py_ssize_t parentpos, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000417 int cmp;
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000418
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000419 assert(PyList_Check(heap));
Raymond Hettinger90e93382014-05-03 18:45:54 -0700420 size = PyList_GET_SIZE(heap);
421 if (pos >= size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000422 PyErr_SetString(PyExc_IndexError, "index out of range");
423 return -1;
424 }
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000425
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000426 /* Follow the path to the root, moving parents down until finding
427 a place newitem fits. */
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700428 arr = _PyList_ITEMS(heap);
429 newitem = arr[pos];
Raymond Hettinger90e93382014-05-03 18:45:54 -0700430 while (pos > startpos) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000431 parentpos = (pos - 1) >> 1;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700432 parent = arr[parentpos];
Pablo Galindo79f89e62020-01-23 14:07:05 +0000433 Py_INCREF(parent);
434 Py_INCREF(newitem);
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +0000435 cmp = PyObject_RichCompareBool(parent, newitem, Py_LT);
Pablo Galindo79f89e62020-01-23 14:07:05 +0000436 Py_DECREF(parent);
437 Py_DECREF(newitem);
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700438 if (cmp < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000439 return -1;
Raymond Hettinger90e93382014-05-03 18:45:54 -0700440 if (size != PyList_GET_SIZE(heap)) {
441 PyErr_SetString(PyExc_RuntimeError,
442 "list changed size during iteration");
443 return -1;
444 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000445 if (cmp == 0)
446 break;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700447 arr = _PyList_ITEMS(heap);
448 parent = arr[parentpos];
449 newitem = arr[pos];
450 arr[parentpos] = newitem;
451 arr[pos] = parent;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000452 pos = parentpos;
453 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000454 return 0;
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000455}
456
457static int
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700458siftup_max(PyListObject *heap, Py_ssize_t pos)
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000459{
Raymond Hettingerc784c6d2015-05-15 21:01:13 -0700460 Py_ssize_t startpos, endpos, childpos, limit;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700461 PyObject *tmp1, *tmp2, **arr;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000462 int cmp;
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000463
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000464 assert(PyList_Check(heap));
465 endpos = PyList_GET_SIZE(heap);
466 startpos = pos;
467 if (pos >= endpos) {
468 PyErr_SetString(PyExc_IndexError, "index out of range");
469 return -1;
470 }
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000471
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000472 /* Bubble up the smaller child until hitting a leaf. */
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700473 arr = _PyList_ITEMS(heap);
Raymond Hettingercfe5b6c2015-07-20 00:25:50 -0400474 limit = endpos >> 1; /* smallest pos that has no child */
Raymond Hettingerc9926082014-05-03 15:22:07 -0700475 while (pos < limit) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000476 /* Set childpos to index of smaller child. */
Raymond Hettingerc9926082014-05-03 15:22:07 -0700477 childpos = 2*pos + 1; /* leftmost child position */
Raymond Hettingerc784c6d2015-05-15 21:01:13 -0700478 if (childpos + 1 < endpos) {
Pablo Galindo79f89e62020-01-23 14:07:05 +0000479 PyObject* a = arr[childpos + 1];
480 PyObject* b = arr[childpos];
481 Py_INCREF(a);
482 Py_INCREF(b);
483 cmp = PyObject_RichCompareBool(a, b, Py_LT);
484 Py_DECREF(a);
485 Py_DECREF(b);
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700486 if (cmp < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000487 return -1;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700488 childpos += ((unsigned)cmp ^ 1); /* increment when cmp==0 */
Raymond Hettinger2300bf22015-12-07 20:45:16 -0800489 arr = _PyList_ITEMS(heap); /* arr may have changed */
Raymond Hettinger871620d2014-05-03 18:36:48 -0700490 if (endpos != PyList_GET_SIZE(heap)) {
491 PyErr_SetString(PyExc_RuntimeError,
492 "list changed size during iteration");
493 return -1;
494 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000495 }
496 /* Move the smaller child up. */
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700497 tmp1 = arr[childpos];
498 tmp2 = arr[pos];
499 arr[childpos] = tmp2;
500 arr[pos] = tmp1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000501 pos = childpos;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000502 }
Raymond Hettinger871620d2014-05-03 18:36:48 -0700503 /* Bubble it up to its final resting place (by sifting its parents down). */
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700504 return siftdown_max(heap, startpos, pos);
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000505}
506
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100507
508/*[clinic input]
509_heapq._heappop_max
510
511 heap: object
512 /
513
514Maxheap variant of heappop.
515[clinic start generated code]*/
516
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000517static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100518_heapq__heappop_max(PyObject *module, PyObject *heap)
519/*[clinic end generated code: output=acd30acf6384b13c input=62ede3ba9117f541]*/
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000520{
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700521 return heappop_internal(heap, siftup_max);
522}
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000523
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100524/*[clinic input]
525_heapq._heapreplace_max
526
527 heap: object
528 item: object
529 /
530
531Maxheap variant of heapreplace.
532[clinic start generated code]*/
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000533
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700534static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100535_heapq__heapreplace_max_impl(PyObject *module, PyObject *heap,
536 PyObject *item)
537/*[clinic end generated code: output=8ad7545e4a5e8adb input=6d8f25131e0f0e5f]*/
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700538{
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100539 return heapreplace_internal(heap, item, siftup_max);
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000540}
541
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100542/*[clinic input]
543_heapq._heapify_max
544
545 heap: object
546 /
547
548Maxheap variant of heapify.
549[clinic start generated code]*/
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000550
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700551static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100552_heapq__heapify_max(PyObject *module, PyObject *heap)
553/*[clinic end generated code: output=1c6bb6b60d6a2133 input=cdfcc6835b14110d]*/
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700554{
555 return heapify_internal(heap, siftup_max);
556}
557
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700558
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000559static PyMethodDef heapq_methods[] = {
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100560 _HEAPQ_HEAPPUSH_METHODDEF
561 _HEAPQ_HEAPPUSHPOP_METHODDEF
562 _HEAPQ_HEAPPOP_METHODDEF
563 _HEAPQ_HEAPREPLACE_METHODDEF
564 _HEAPQ_HEAPIFY_METHODDEF
565 _HEAPQ__HEAPPOP_MAX_METHODDEF
566 _HEAPQ__HEAPIFY_MAX_METHODDEF
567 _HEAPQ__HEAPREPLACE_MAX_METHODDEF
568 {NULL, NULL} /* sentinel */
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000569};
570
571PyDoc_STRVAR(module_doc,
572"Heap queue algorithm (a.k.a. priority queue).\n\
573\n\
574Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for\n\
575all k, counting elements from 0. For the sake of comparison,\n\
576non-existing elements are considered to be infinite. The interesting\n\
577property of a heap is that a[0] is always its smallest element.\n\
578\n\
579Usage:\n\
580\n\
581heap = [] # creates an empty heap\n\
582heappush(heap, item) # pushes a new item on the heap\n\
583item = heappop(heap) # pops the smallest item from the heap\n\
584item = heap[0] # smallest item on the heap without popping it\n\
585heapify(x) # transforms list into a heap, in-place, in linear time\n\
586item = heapreplace(heap, item) # pops and returns smallest item, and adds\n\
587 # new item; the heap size is unchanged\n\
588\n\
589Our API differs from textbook heap algorithms as follows:\n\
590\n\
591- We use 0-based indexing. This makes the relationship between the\n\
592 index for a node and the indexes for its children slightly less\n\
593 obvious, but is more suitable since Python uses 0-based indexing.\n\
594\n\
595- Our heappop() method returns the smallest item, not the largest.\n\
596\n\
597These two make it possible to view the heap as a regular Python list\n\
598without surprises: heap[0] is the smallest item, and heap.sort()\n\
599maintains the heap invariant!\n");
600
601
602PyDoc_STRVAR(__about__,
603"Heap queues\n\
604\n\
Neal Norwitzc1786ea2007-08-23 23:58:43 +0000605[explanation by Fran\xc3\xa7ois Pinard]\n\
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000606\n\
607Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for\n\
608all k, counting elements from 0. For the sake of comparison,\n\
609non-existing elements are considered to be infinite. The interesting\n\
610property of a heap is that a[0] is always its smallest element.\n"
611"\n\
612The strange invariant above is meant to be an efficient memory\n\
613representation for a tournament. The numbers below are `k', not a[k]:\n\
614\n\
615 0\n\
616\n\
617 1 2\n\
618\n\
619 3 4 5 6\n\
620\n\
621 7 8 9 10 11 12 13 14\n\
622\n\
623 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30\n\
624\n\
625\n\
626In the tree above, each cell `k' is topping `2*k+1' and `2*k+2'. In\n\
Martin Panter6245cb32016-04-15 02:14:19 +0000627a usual binary tournament we see in sports, each cell is the winner\n\
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000628over the two cells it tops, and we can trace the winner down the tree\n\
629to see all opponents s/he had. However, in many computer applications\n\
630of such tournaments, we do not need to trace the history of a winner.\n\
631To be more memory efficient, when a winner is promoted, we try to\n\
632replace it by something else at a lower level, and the rule becomes\n\
633that a cell and the two cells it tops contain three different items,\n\
634but the top cell \"wins\" over the two topped cells.\n"
635"\n\
636If this heap invariant is protected at all time, index 0 is clearly\n\
637the overall winner. The simplest algorithmic way to remove it and\n\
638find the \"next\" winner is to move some loser (let's say cell 30 in the\n\
639diagram above) into the 0 position, and then percolate this new 0 down\n\
640the tree, exchanging values, until the invariant is re-established.\n\
641This is clearly logarithmic on the total number of items in the tree.\n\
642By iterating over all items, you get an O(n ln n) sort.\n"
643"\n\
644A nice feature of this sort is that you can efficiently insert new\n\
645items while the sort is going on, provided that the inserted items are\n\
646not \"better\" than the last 0'th element you extracted. This is\n\
647especially useful in simulation contexts, where the tree holds all\n\
648incoming events, and the \"win\" condition means the smallest scheduled\n\
649time. When an event schedule other events for execution, they are\n\
650scheduled into the future, so they can easily go into the heap. So, a\n\
651heap is a good structure for implementing schedulers (this is what I\n\
652used for my MIDI sequencer :-).\n"
653"\n\
654Various structures for implementing schedulers have been extensively\n\
655studied, and heaps are good for this, as they are reasonably speedy,\n\
656the speed is almost constant, and the worst case is not much different\n\
657than the average case. However, there are other representations which\n\
658are more efficient overall, yet the worst cases might be terrible.\n"
659"\n\
660Heaps are also very useful in big disk sorts. You most probably all\n\
661know that a big sort implies producing \"runs\" (which are pre-sorted\n\
662sequences, which size is usually related to the amount of CPU memory),\n\
663followed by a merging passes for these runs, which merging is often\n\
664very cleverly organised[1]. It is very important that the initial\n\
665sort produces the longest runs possible. Tournaments are a good way\n\
666to that. If, using all the memory available to hold a tournament, you\n\
667replace and percolate items that happen to fit the current run, you'll\n\
668produce runs which are twice the size of the memory for random input,\n\
669and much better for input fuzzily ordered.\n"
670"\n\
671Moreover, if you output the 0'th item on disk and get an input which\n\
672may not fit in the current tournament (because the value \"wins\" over\n\
673the last output value), it cannot fit in the heap, so the size of the\n\
674heap decreases. The freed memory could be cleverly reused immediately\n\
675for progressively building a second heap, which grows at exactly the\n\
676same rate the first heap is melting. When the first heap completely\n\
677vanishes, you switch heaps and start a new run. Clever and quite\n\
678effective!\n\
679\n\
680In a word, heaps are useful memory structures to know. I use them in\n\
681a few applications, and I think it is good to keep a `heap' module\n\
682around. :-)\n"
683"\n\
684--------------------\n\
685[1] The disk balancing algorithms which are current, nowadays, are\n\
686more annoying than clever, and this is a consequence of the seeking\n\
687capabilities of the disks. On devices which cannot seek, like big\n\
688tape drives, the story was quite different, and one had to be very\n\
689clever to ensure (far in advance) that each tape movement will be the\n\
690most effective possible (that is, will best participate at\n\
691\"progressing\" the merge). Some tapes were even able to read\n\
692backwards, and this was also used to avoid the rewinding time.\n\
693Believe me, real good tape sorts were quite spectacular to watch!\n\
694From all times, sorting has always been a Great Art! :-)\n");
695
Martin v. Löwis1a214512008-06-11 05:26:20 +0000696
697static struct PyModuleDef _heapqmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000698 PyModuleDef_HEAD_INIT,
699 "_heapq",
700 module_doc,
701 -1,
702 heapq_methods,
703 NULL,
704 NULL,
705 NULL,
706 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000707};
708
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000709PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000710PyInit__heapq(void)
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000711{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000712 PyObject *m, *about;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000713
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000714 m = PyModule_Create(&_heapqmodule);
715 if (m == NULL)
716 return NULL;
717 about = PyUnicode_DecodeUTF8(__about__, strlen(__about__), NULL);
718 PyModule_AddObject(m, "__about__", about);
719 return m;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000720}
721