blob: 20468c28f24234ad7f5374408d60eaf2eee6e88b [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"
Victor Stinnerc45dbe932020-06-22 17:39:32 +020010#include "pycore_list.h" // _PyList_ITEMS()
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000011
Pablo Galindoe2f48bf2018-09-28 20:39:43 +010012#include "clinic/_heapqmodule.c.h"
13
Victor Stinnerc45dbe932020-06-22 17:39:32 +020014
Pablo Galindoe2f48bf2018-09-28 20:39:43 +010015/*[clinic input]
16module _heapq
17[clinic start generated code]*/
18/*[clinic end generated code: output=da39a3ee5e6b4b0d input=d7cca0a2e4c0ceb3]*/
19
Georg Brandlf78e02b2008-06-10 17:40:04 +000020static int
Raymond Hettinger48f68d02014-06-14 16:43:35 -070021siftdown(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000022{
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070023 PyObject *newitem, *parent, **arr;
Raymond Hettinger90e93382014-05-03 18:45:54 -070024 Py_ssize_t parentpos, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000025 int cmp;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000026
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000027 assert(PyList_Check(heap));
Antoine Pitrou44d52142013-03-04 20:30:01 +010028 size = PyList_GET_SIZE(heap);
29 if (pos >= size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000030 PyErr_SetString(PyExc_IndexError, "index out of range");
31 return -1;
32 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000033
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000034 /* Follow the path to the root, moving parents down until finding
35 a place newitem fits. */
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070036 arr = _PyList_ITEMS(heap);
37 newitem = arr[pos];
Raymond Hettinger90e93382014-05-03 18:45:54 -070038 while (pos > startpos) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000039 parentpos = (pos - 1) >> 1;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070040 parent = arr[parentpos];
Pablo Galindo79f89e62020-01-23 14:07:05 +000041 Py_INCREF(newitem);
42 Py_INCREF(parent);
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +000043 cmp = PyObject_RichCompareBool(newitem, parent, Py_LT);
Pablo Galindo79f89e62020-01-23 14:07:05 +000044 Py_DECREF(parent);
45 Py_DECREF(newitem);
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070046 if (cmp < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000047 return -1;
Antoine Pitrou44d52142013-03-04 20:30:01 +010048 if (size != PyList_GET_SIZE(heap)) {
Antoine Pitrou44d52142013-03-04 20:30:01 +010049 PyErr_SetString(PyExc_RuntimeError,
50 "list changed size during iteration");
51 return -1;
52 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000053 if (cmp == 0)
54 break;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070055 arr = _PyList_ITEMS(heap);
56 parent = arr[parentpos];
57 newitem = arr[pos];
58 arr[parentpos] = newitem;
59 arr[pos] = parent;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000060 pos = parentpos;
61 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000062 return 0;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000063}
64
65static int
Raymond Hettinger48f68d02014-06-14 16:43:35 -070066siftup(PyListObject *heap, Py_ssize_t pos)
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000067{
Raymond Hettingerc784c6d2015-05-15 21:01:13 -070068 Py_ssize_t startpos, endpos, childpos, limit;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070069 PyObject *tmp1, *tmp2, **arr;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000070 int cmp;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000071
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000072 assert(PyList_Check(heap));
Raymond Hettinger871620d2014-05-03 18:36:48 -070073 endpos = PyList_GET_SIZE(heap);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000074 startpos = pos;
75 if (pos >= endpos) {
76 PyErr_SetString(PyExc_IndexError, "index out of range");
77 return -1;
78 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000079
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000080 /* Bubble up the smaller child until hitting a leaf. */
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070081 arr = _PyList_ITEMS(heap);
Raymond Hettingercfe5b6c2015-07-20 00:25:50 -040082 limit = endpos >> 1; /* smallest pos that has no child */
Raymond Hettingerc9926082014-05-03 15:22:07 -070083 while (pos < limit) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000084 /* Set childpos to index of smaller child. */
Raymond Hettingerc9926082014-05-03 15:22:07 -070085 childpos = 2*pos + 1; /* leftmost child position */
Raymond Hettingerc784c6d2015-05-15 21:01:13 -070086 if (childpos + 1 < endpos) {
Pablo Galindo79f89e62020-01-23 14:07:05 +000087 PyObject* a = arr[childpos];
88 PyObject* b = arr[childpos + 1];
89 Py_INCREF(a);
90 Py_INCREF(b);
91 cmp = PyObject_RichCompareBool(a, b, Py_LT);
92 Py_DECREF(a);
93 Py_DECREF(b);
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070094 if (cmp < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000095 return -1;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070096 childpos += ((unsigned)cmp ^ 1); /* increment when cmp==0 */
Raymond Hettinger2300bf22015-12-07 20:45:16 -080097 arr = _PyList_ITEMS(heap); /* arr may have changed */
Raymond Hettinger871620d2014-05-03 18:36:48 -070098 if (endpos != PyList_GET_SIZE(heap)) {
99 PyErr_SetString(PyExc_RuntimeError,
100 "list changed size during iteration");
101 return -1;
102 }
Antoine Pitrou44d52142013-03-04 20:30:01 +0100103 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000104 /* Move the smaller child up. */
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700105 tmp1 = arr[childpos];
106 tmp2 = arr[pos];
107 arr[childpos] = tmp2;
108 arr[pos] = tmp1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000109 pos = childpos;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000110 }
Raymond Hettinger871620d2014-05-03 18:36:48 -0700111 /* Bubble it up to its final resting place (by sifting its parents down). */
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700112 return siftdown(heap, startpos, pos);
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000113}
114
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100115/*[clinic input]
116_heapq.heappush
117
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700118 heap: object(subclass_of='&PyList_Type')
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100119 item: object
120 /
121
122Push item onto heap, maintaining the heap invariant.
123[clinic start generated code]*/
124
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000125static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100126_heapq_heappush_impl(PyObject *module, PyObject *heap, PyObject *item)
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700127/*[clinic end generated code: output=912c094f47663935 input=7c69611f3698aceb]*/
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000128{
Raymond Hettingera032e462015-05-11 10:32:57 -0700129 if (PyList_Append(heap, item))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000130 return NULL;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000131
Raymond Hettingera032e462015-05-11 10:32:57 -0700132 if (siftdown((PyListObject *)heap, 0, PyList_GET_SIZE(heap)-1))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000133 return NULL;
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700134 Py_RETURN_NONE;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000135}
136
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000137static PyObject *
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700138heappop_internal(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000139{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000140 PyObject *lastelt, *returnitem;
141 Py_ssize_t n;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000142
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700143 /* raises IndexError if the heap is empty */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000144 n = PyList_GET_SIZE(heap);
145 if (n == 0) {
146 PyErr_SetString(PyExc_IndexError, "index out of range");
147 return NULL;
148 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000149
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000150 lastelt = PyList_GET_ITEM(heap, n-1) ;
151 Py_INCREF(lastelt);
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700152 if (PyList_SetSlice(heap, n-1, n, NULL)) {
Victor Stinner764a46d2013-07-17 21:50:21 +0200153 Py_DECREF(lastelt);
154 return NULL;
155 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000156 n--;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000157
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000158 if (!n)
159 return lastelt;
160 returnitem = PyList_GET_ITEM(heap, 0);
161 PyList_SET_ITEM(heap, 0, lastelt);
Raymond Hettingera032e462015-05-11 10:32:57 -0700162 if (siftup_func((PyListObject *)heap, 0)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000163 Py_DECREF(returnitem);
164 return NULL;
165 }
166 return returnitem;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000167}
168
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100169/*[clinic input]
170_heapq.heappop
171
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700172 heap: object(subclass_of='&PyList_Type')
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100173 /
174
175Pop the smallest item off the heap, maintaining the heap invariant.
176[clinic start generated code]*/
177
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700178static PyObject *
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700179_heapq_heappop_impl(PyObject *module, PyObject *heap)
180/*[clinic end generated code: output=96dfe82d37d9af76 input=91487987a583c856]*/
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700181{
182 return heappop_internal(heap, siftup);
183}
184
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000185static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100186heapreplace_internal(PyObject *heap, PyObject *item, int siftup_func(PyListObject *, Py_ssize_t))
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000187{
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100188 PyObject *returnitem;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000189
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700190 if (PyList_GET_SIZE(heap) == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000191 PyErr_SetString(PyExc_IndexError, "index out of range");
192 return NULL;
193 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000194
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000195 returnitem = PyList_GET_ITEM(heap, 0);
196 Py_INCREF(item);
197 PyList_SET_ITEM(heap, 0, item);
Raymond Hettingera032e462015-05-11 10:32:57 -0700198 if (siftup_func((PyListObject *)heap, 0)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000199 Py_DECREF(returnitem);
200 return NULL;
201 }
202 return returnitem;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000203}
204
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100205
206/*[clinic input]
207_heapq.heapreplace
208
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700209 heap: object(subclass_of='&PyList_Type')
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100210 item: object
211 /
212
213Pop and return the current smallest value, and add the new item.
214
215This is more efficient than heappop() followed by heappush(), and can be
216more appropriate when using a fixed-size heap. Note that the value
217returned may be larger than item! That constrains reasonable uses of
218this routine unless written as part of a conditional replacement:
219
220 if item > heap[0]:
221 item = heapreplace(heap, item)
222[clinic start generated code]*/
223
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700224static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100225_heapq_heapreplace_impl(PyObject *module, PyObject *heap, PyObject *item)
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700226/*[clinic end generated code: output=82ea55be8fbe24b4 input=719202ac02ba10c8]*/
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700227{
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100228 return heapreplace_internal(heap, item, siftup);
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700229}
230
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100231/*[clinic input]
232_heapq.heappushpop
233
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700234 heap: object(subclass_of='&PyList_Type')
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100235 item: object
236 /
237
238Push item on the heap, then pop and return the smallest item from the heap.
239
240The combined action runs more efficiently than heappush() followed by
241a separate call to heappop().
242[clinic start generated code]*/
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000243
244static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100245_heapq_heappushpop_impl(PyObject *module, PyObject *heap, PyObject *item)
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700246/*[clinic end generated code: output=67231dc98ed5774f input=5dc701f1eb4a4aa7]*/
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000247{
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100248 PyObject *returnitem;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000249 int cmp;
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000250
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700251 if (PyList_GET_SIZE(heap) == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000252 Py_INCREF(item);
253 return item;
254 }
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000255
Pablo Galindo79f89e62020-01-23 14:07:05 +0000256 PyObject* top = PyList_GET_ITEM(heap, 0);
257 Py_INCREF(top);
258 cmp = PyObject_RichCompareBool(top, item, Py_LT);
259 Py_DECREF(top);
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700260 if (cmp < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000261 return NULL;
262 if (cmp == 0) {
263 Py_INCREF(item);
264 return item;
265 }
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000266
Raymond Hettingerb9db9e12015-05-11 19:58:56 -0700267 if (PyList_GET_SIZE(heap) == 0) {
268 PyErr_SetString(PyExc_IndexError, "index out of range");
269 return NULL;
270 }
271
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000272 returnitem = PyList_GET_ITEM(heap, 0);
273 Py_INCREF(item);
274 PyList_SET_ITEM(heap, 0, item);
Raymond Hettingera032e462015-05-11 10:32:57 -0700275 if (siftup((PyListObject *)heap, 0)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000276 Py_DECREF(returnitem);
277 return NULL;
278 }
279 return returnitem;
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000280}
281
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700282static Py_ssize_t
283keep_top_bit(Py_ssize_t n)
284{
285 int i = 0;
286
287 while (n > 1) {
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700288 n >>= 1;
Raymond Hettingerd69755d2015-05-15 17:53:52 -0700289 i++;
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700290 }
291 return n << i;
292}
293
294/* Cache friendly version of heapify()
295 -----------------------------------
296
297 Build-up a heap in O(n) time by performing siftup() operations
298 on nodes whose children are already heaps.
299
300 The simplest way is to sift the nodes in reverse order from
301 n//2-1 to 0 inclusive. The downside is that children may be
302 out of cache by the time their parent is reached.
303
304 A better way is to not wait for the children to go out of cache.
305 Once a sibling pair of child nodes have been sifted, immediately
306 sift their parent node (while the children are still in cache).
307
308 Both ways build child heaps before their parents, so both ways
309 do the exact same number of comparisons and produce exactly
310 the same heap. The only difference is that the traversal
311 order is optimized for cache efficiency.
312*/
313
314static PyObject *
315cache_friendly_heapify(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
316{
317 Py_ssize_t i, j, m, mhalf, leftmost;
318
319 m = PyList_GET_SIZE(heap) >> 1; /* index of first childless node */
320 leftmost = keep_top_bit(m + 1) - 1; /* leftmost node in row of m */
321 mhalf = m >> 1; /* parent of first childless node */
322
323 for (i = leftmost - 1 ; i >= mhalf ; i--) {
324 j = i;
325 while (1) {
326 if (siftup_func((PyListObject *)heap, j))
327 return NULL;
328 if (!(j & 1))
329 break;
330 j >>= 1;
331 }
332 }
333
334 for (i = m - 1 ; i >= leftmost ; i--) {
335 j = i;
336 while (1) {
337 if (siftup_func((PyListObject *)heap, j))
338 return NULL;
339 if (!(j & 1))
340 break;
341 j >>= 1;
342 }
343 }
344 Py_RETURN_NONE;
345}
346
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000347static PyObject *
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700348heapify_internal(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000349{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000350 Py_ssize_t i, n;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000351
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700352 /* For heaps likely to be bigger than L1 cache, we use the cache
353 friendly heapify function. For smaller heaps that fit entirely
354 in cache, we prefer the simpler algorithm with less branching.
355 */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000356 n = PyList_GET_SIZE(heap);
Raymond Hettinger63648802015-05-12 21:40:50 -0700357 if (n > 2500)
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700358 return cache_friendly_heapify(heap, siftup_func);
359
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000360 /* Transform bottom-up. The largest index there's any point to
361 looking at is the largest with a child index in-range, so must
362 have 2*i + 1 < n, or i < (n-1)/2. If n is even = 2*j, this is
363 (2*j-1)/2 = j-1/2 so j-1 is the largest, which is n//2 - 1. If
364 n is odd = 2*j+1, this is (2*j+1-1)/2 = j so j-1 is the largest,
365 and that's again n//2-1.
366 */
Raymond Hettingercfe5b6c2015-07-20 00:25:50 -0400367 for (i = (n >> 1) - 1 ; i >= 0 ; i--)
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700368 if (siftup_func((PyListObject *)heap, i))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000369 return NULL;
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700370 Py_RETURN_NONE;
371}
372
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100373/*[clinic input]
374_heapq.heapify
375
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700376 heap: object(subclass_of='&PyList_Type')
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100377 /
378
379Transform list into a heap, in-place, in O(len(heap)) time.
380[clinic start generated code]*/
381
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700382static PyObject *
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700383_heapq_heapify_impl(PyObject *module, PyObject *heap)
384/*[clinic end generated code: output=e63a636fcf83d6d0 input=53bb7a2166febb73]*/
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700385{
386 return heapify_internal(heap, siftup);
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000387}
388
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000389static int
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700390siftdown_max(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000391{
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700392 PyObject *newitem, *parent, **arr;
Raymond Hettinger90e93382014-05-03 18:45:54 -0700393 Py_ssize_t parentpos, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000394 int cmp;
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000395
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000396 assert(PyList_Check(heap));
Raymond Hettinger90e93382014-05-03 18:45:54 -0700397 size = PyList_GET_SIZE(heap);
398 if (pos >= size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000399 PyErr_SetString(PyExc_IndexError, "index out of range");
400 return -1;
401 }
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000402
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000403 /* Follow the path to the root, moving parents down until finding
404 a place newitem fits. */
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700405 arr = _PyList_ITEMS(heap);
406 newitem = arr[pos];
Raymond Hettinger90e93382014-05-03 18:45:54 -0700407 while (pos > startpos) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000408 parentpos = (pos - 1) >> 1;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700409 parent = arr[parentpos];
Pablo Galindo79f89e62020-01-23 14:07:05 +0000410 Py_INCREF(parent);
411 Py_INCREF(newitem);
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +0000412 cmp = PyObject_RichCompareBool(parent, newitem, Py_LT);
Pablo Galindo79f89e62020-01-23 14:07:05 +0000413 Py_DECREF(parent);
414 Py_DECREF(newitem);
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700415 if (cmp < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000416 return -1;
Raymond Hettinger90e93382014-05-03 18:45:54 -0700417 if (size != PyList_GET_SIZE(heap)) {
418 PyErr_SetString(PyExc_RuntimeError,
419 "list changed size during iteration");
420 return -1;
421 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000422 if (cmp == 0)
423 break;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700424 arr = _PyList_ITEMS(heap);
425 parent = arr[parentpos];
426 newitem = arr[pos];
427 arr[parentpos] = newitem;
428 arr[pos] = parent;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000429 pos = parentpos;
430 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000431 return 0;
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000432}
433
434static int
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700435siftup_max(PyListObject *heap, Py_ssize_t pos)
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000436{
Raymond Hettingerc784c6d2015-05-15 21:01:13 -0700437 Py_ssize_t startpos, endpos, childpos, limit;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700438 PyObject *tmp1, *tmp2, **arr;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000439 int cmp;
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000440
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000441 assert(PyList_Check(heap));
442 endpos = PyList_GET_SIZE(heap);
443 startpos = pos;
444 if (pos >= endpos) {
445 PyErr_SetString(PyExc_IndexError, "index out of range");
446 return -1;
447 }
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000448
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000449 /* Bubble up the smaller child until hitting a leaf. */
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700450 arr = _PyList_ITEMS(heap);
Raymond Hettingercfe5b6c2015-07-20 00:25:50 -0400451 limit = endpos >> 1; /* smallest pos that has no child */
Raymond Hettingerc9926082014-05-03 15:22:07 -0700452 while (pos < limit) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000453 /* Set childpos to index of smaller child. */
Raymond Hettingerc9926082014-05-03 15:22:07 -0700454 childpos = 2*pos + 1; /* leftmost child position */
Raymond Hettingerc784c6d2015-05-15 21:01:13 -0700455 if (childpos + 1 < endpos) {
Pablo Galindo79f89e62020-01-23 14:07:05 +0000456 PyObject* a = arr[childpos + 1];
457 PyObject* b = arr[childpos];
458 Py_INCREF(a);
459 Py_INCREF(b);
460 cmp = PyObject_RichCompareBool(a, b, Py_LT);
461 Py_DECREF(a);
462 Py_DECREF(b);
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700463 if (cmp < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000464 return -1;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700465 childpos += ((unsigned)cmp ^ 1); /* increment when cmp==0 */
Raymond Hettinger2300bf22015-12-07 20:45:16 -0800466 arr = _PyList_ITEMS(heap); /* arr may have changed */
Raymond Hettinger871620d2014-05-03 18:36:48 -0700467 if (endpos != PyList_GET_SIZE(heap)) {
468 PyErr_SetString(PyExc_RuntimeError,
469 "list changed size during iteration");
470 return -1;
471 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000472 }
473 /* Move the smaller child up. */
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700474 tmp1 = arr[childpos];
475 tmp2 = arr[pos];
476 arr[childpos] = tmp2;
477 arr[pos] = tmp1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000478 pos = childpos;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000479 }
Raymond Hettinger871620d2014-05-03 18:36:48 -0700480 /* Bubble it up to its final resting place (by sifting its parents down). */
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700481 return siftdown_max(heap, startpos, pos);
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000482}
483
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100484
485/*[clinic input]
486_heapq._heappop_max
487
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700488 heap: object(subclass_of='&PyList_Type')
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100489 /
490
491Maxheap variant of heappop.
492[clinic start generated code]*/
493
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000494static PyObject *
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700495_heapq__heappop_max_impl(PyObject *module, PyObject *heap)
496/*[clinic end generated code: output=9e77aadd4e6a8760 input=362c06e1c7484793]*/
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000497{
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700498 return heappop_internal(heap, siftup_max);
499}
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000500
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100501/*[clinic input]
502_heapq._heapreplace_max
503
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700504 heap: object(subclass_of='&PyList_Type')
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100505 item: object
506 /
507
508Maxheap variant of heapreplace.
509[clinic start generated code]*/
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000510
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700511static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100512_heapq__heapreplace_max_impl(PyObject *module, PyObject *heap,
513 PyObject *item)
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700514/*[clinic end generated code: output=8ad7545e4a5e8adb input=f2dd27cbadb948d7]*/
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700515{
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100516 return heapreplace_internal(heap, item, siftup_max);
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000517}
518
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100519/*[clinic input]
520_heapq._heapify_max
521
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700522 heap: object(subclass_of='&PyList_Type')
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100523 /
524
525Maxheap variant of heapify.
526[clinic start generated code]*/
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000527
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700528static PyObject *
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700529_heapq__heapify_max_impl(PyObject *module, PyObject *heap)
530/*[clinic end generated code: output=2cb028beb4a8b65e input=c1f765ee69f124b8]*/
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700531{
532 return heapify_internal(heap, siftup_max);
533}
534
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000535static PyMethodDef heapq_methods[] = {
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100536 _HEAPQ_HEAPPUSH_METHODDEF
537 _HEAPQ_HEAPPUSHPOP_METHODDEF
538 _HEAPQ_HEAPPOP_METHODDEF
539 _HEAPQ_HEAPREPLACE_METHODDEF
540 _HEAPQ_HEAPIFY_METHODDEF
541 _HEAPQ__HEAPPOP_MAX_METHODDEF
542 _HEAPQ__HEAPIFY_MAX_METHODDEF
543 _HEAPQ__HEAPREPLACE_MAX_METHODDEF
544 {NULL, NULL} /* sentinel */
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000545};
546
547PyDoc_STRVAR(module_doc,
548"Heap queue algorithm (a.k.a. priority queue).\n\
549\n\
550Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for\n\
551all k, counting elements from 0. For the sake of comparison,\n\
552non-existing elements are considered to be infinite. The interesting\n\
553property of a heap is that a[0] is always its smallest element.\n\
554\n\
555Usage:\n\
556\n\
557heap = [] # creates an empty heap\n\
558heappush(heap, item) # pushes a new item on the heap\n\
559item = heappop(heap) # pops the smallest item from the heap\n\
560item = heap[0] # smallest item on the heap without popping it\n\
561heapify(x) # transforms list into a heap, in-place, in linear time\n\
562item = heapreplace(heap, item) # pops and returns smallest item, and adds\n\
563 # new item; the heap size is unchanged\n\
564\n\
565Our API differs from textbook heap algorithms as follows:\n\
566\n\
567- We use 0-based indexing. This makes the relationship between the\n\
568 index for a node and the indexes for its children slightly less\n\
569 obvious, but is more suitable since Python uses 0-based indexing.\n\
570\n\
571- Our heappop() method returns the smallest item, not the largest.\n\
572\n\
573These two make it possible to view the heap as a regular Python list\n\
574without surprises: heap[0] is the smallest item, and heap.sort()\n\
575maintains the heap invariant!\n");
576
577
578PyDoc_STRVAR(__about__,
579"Heap queues\n\
580\n\
Neal Norwitzc1786ea2007-08-23 23:58:43 +0000581[explanation by Fran\xc3\xa7ois Pinard]\n\
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000582\n\
583Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for\n\
584all k, counting elements from 0. For the sake of comparison,\n\
585non-existing elements are considered to be infinite. The interesting\n\
586property of a heap is that a[0] is always its smallest element.\n"
587"\n\
588The strange invariant above is meant to be an efficient memory\n\
589representation for a tournament. The numbers below are `k', not a[k]:\n\
590\n\
591 0\n\
592\n\
593 1 2\n\
594\n\
595 3 4 5 6\n\
596\n\
597 7 8 9 10 11 12 13 14\n\
598\n\
599 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30\n\
600\n\
601\n\
602In the tree above, each cell `k' is topping `2*k+1' and `2*k+2'. In\n\
Martin Panter6245cb32016-04-15 02:14:19 +0000603a usual binary tournament we see in sports, each cell is the winner\n\
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000604over the two cells it tops, and we can trace the winner down the tree\n\
605to see all opponents s/he had. However, in many computer applications\n\
606of such tournaments, we do not need to trace the history of a winner.\n\
607To be more memory efficient, when a winner is promoted, we try to\n\
608replace it by something else at a lower level, and the rule becomes\n\
609that a cell and the two cells it tops contain three different items,\n\
610but the top cell \"wins\" over the two topped cells.\n"
611"\n\
612If this heap invariant is protected at all time, index 0 is clearly\n\
613the overall winner. The simplest algorithmic way to remove it and\n\
614find the \"next\" winner is to move some loser (let's say cell 30 in the\n\
615diagram above) into the 0 position, and then percolate this new 0 down\n\
616the tree, exchanging values, until the invariant is re-established.\n\
617This is clearly logarithmic on the total number of items in the tree.\n\
618By iterating over all items, you get an O(n ln n) sort.\n"
619"\n\
620A nice feature of this sort is that you can efficiently insert new\n\
621items while the sort is going on, provided that the inserted items are\n\
622not \"better\" than the last 0'th element you extracted. This is\n\
623especially useful in simulation contexts, where the tree holds all\n\
624incoming events, and the \"win\" condition means the smallest scheduled\n\
625time. When an event schedule other events for execution, they are\n\
626scheduled into the future, so they can easily go into the heap. So, a\n\
627heap is a good structure for implementing schedulers (this is what I\n\
628used for my MIDI sequencer :-).\n"
629"\n\
630Various structures for implementing schedulers have been extensively\n\
631studied, and heaps are good for this, as they are reasonably speedy,\n\
632the speed is almost constant, and the worst case is not much different\n\
633than the average case. However, there are other representations which\n\
634are more efficient overall, yet the worst cases might be terrible.\n"
635"\n\
636Heaps are also very useful in big disk sorts. You most probably all\n\
637know that a big sort implies producing \"runs\" (which are pre-sorted\n\
638sequences, which size is usually related to the amount of CPU memory),\n\
639followed by a merging passes for these runs, which merging is often\n\
640very cleverly organised[1]. It is very important that the initial\n\
641sort produces the longest runs possible. Tournaments are a good way\n\
642to that. If, using all the memory available to hold a tournament, you\n\
643replace and percolate items that happen to fit the current run, you'll\n\
644produce runs which are twice the size of the memory for random input,\n\
645and much better for input fuzzily ordered.\n"
646"\n\
647Moreover, if you output the 0'th item on disk and get an input which\n\
648may not fit in the current tournament (because the value \"wins\" over\n\
649the last output value), it cannot fit in the heap, so the size of the\n\
650heap decreases. The freed memory could be cleverly reused immediately\n\
651for progressively building a second heap, which grows at exactly the\n\
652same rate the first heap is melting. When the first heap completely\n\
653vanishes, you switch heaps and start a new run. Clever and quite\n\
654effective!\n\
655\n\
656In a word, heaps are useful memory structures to know. I use them in\n\
657a few applications, and I think it is good to keep a `heap' module\n\
658around. :-)\n"
659"\n\
660--------------------\n\
661[1] The disk balancing algorithms which are current, nowadays, are\n\
662more annoying than clever, and this is a consequence of the seeking\n\
663capabilities of the disks. On devices which cannot seek, like big\n\
664tape drives, the story was quite different, and one had to be very\n\
665clever to ensure (far in advance) that each tape movement will be the\n\
666most effective possible (that is, will best participate at\n\
667\"progressing\" the merge). Some tapes were even able to read\n\
668backwards, and this was also used to avoid the rewinding time.\n\
669Believe me, real good tape sorts were quite spectacular to watch!\n\
670From all times, sorting has always been a Great Art! :-)\n");
671
Martin v. Löwis1a214512008-06-11 05:26:20 +0000672
Dong-hee Na4657a8a2020-03-18 23:29:34 +0900673static int
674heapq_exec(PyObject *m)
675{
676 PyObject *about = PyUnicode_FromString(__about__);
677 if (PyModule_AddObject(m, "__about__", about) < 0) {
678 Py_DECREF(about);
679 return -1;
680 }
681 return 0;
682}
683
684static struct PyModuleDef_Slot heapq_slots[] = {
685 {Py_mod_exec, heapq_exec},
686 {0, NULL}
687};
688
Martin v. Löwis1a214512008-06-11 05:26:20 +0000689static struct PyModuleDef _heapqmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000690 PyModuleDef_HEAD_INIT,
691 "_heapq",
692 module_doc,
Dong-hee Na4657a8a2020-03-18 23:29:34 +0900693 0,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000694 heapq_methods,
Dong-hee Na4657a8a2020-03-18 23:29:34 +0900695 heapq_slots,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000696 NULL,
697 NULL,
698 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000699};
700
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000701PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000702PyInit__heapq(void)
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000703{
Dong-hee Na4657a8a2020-03-18 23:29:34 +0900704 return PyModuleDef_Init(&_heapqmodule);
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000705}