blob: 193478d79b45687139179a5fc44b0c0d25fcbe01 [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
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700116 heap: object(subclass_of='&PyList_Type')
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100117 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)
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700125/*[clinic end generated code: output=912c094f47663935 input=7c69611f3698aceb]*/
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000126{
Raymond Hettingera032e462015-05-11 10:32:57 -0700127 if (PyList_Append(heap, item))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000128 return NULL;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000129
Raymond Hettingera032e462015-05-11 10:32:57 -0700130 if (siftdown((PyListObject *)heap, 0, PyList_GET_SIZE(heap)-1))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000131 return NULL;
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700132 Py_RETURN_NONE;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000133}
134
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000135static PyObject *
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700136heappop_internal(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000137{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000138 PyObject *lastelt, *returnitem;
139 Py_ssize_t n;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000140
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700141 /* raises IndexError if the heap is empty */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000142 n = PyList_GET_SIZE(heap);
143 if (n == 0) {
144 PyErr_SetString(PyExc_IndexError, "index out of range");
145 return NULL;
146 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000147
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000148 lastelt = PyList_GET_ITEM(heap, n-1) ;
149 Py_INCREF(lastelt);
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700150 if (PyList_SetSlice(heap, n-1, n, NULL)) {
Victor Stinner764a46d2013-07-17 21:50:21 +0200151 Py_DECREF(lastelt);
152 return NULL;
153 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000154 n--;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000155
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000156 if (!n)
157 return lastelt;
158 returnitem = PyList_GET_ITEM(heap, 0);
159 PyList_SET_ITEM(heap, 0, lastelt);
Raymond Hettingera032e462015-05-11 10:32:57 -0700160 if (siftup_func((PyListObject *)heap, 0)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000161 Py_DECREF(returnitem);
162 return NULL;
163 }
164 return returnitem;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000165}
166
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100167/*[clinic input]
168_heapq.heappop
169
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700170 heap: object(subclass_of='&PyList_Type')
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100171 /
172
173Pop the smallest item off the heap, maintaining the heap invariant.
174[clinic start generated code]*/
175
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700176static PyObject *
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700177_heapq_heappop_impl(PyObject *module, PyObject *heap)
178/*[clinic end generated code: output=96dfe82d37d9af76 input=91487987a583c856]*/
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700179{
180 return heappop_internal(heap, siftup);
181}
182
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000183static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100184heapreplace_internal(PyObject *heap, PyObject *item, int siftup_func(PyListObject *, Py_ssize_t))
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000185{
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100186 PyObject *returnitem;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000187
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700188 if (PyList_GET_SIZE(heap) == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000189 PyErr_SetString(PyExc_IndexError, "index out of range");
190 return NULL;
191 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000192
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000193 returnitem = PyList_GET_ITEM(heap, 0);
194 Py_INCREF(item);
195 PyList_SET_ITEM(heap, 0, item);
Raymond Hettingera032e462015-05-11 10:32:57 -0700196 if (siftup_func((PyListObject *)heap, 0)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000197 Py_DECREF(returnitem);
198 return NULL;
199 }
200 return returnitem;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000201}
202
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100203
204/*[clinic input]
205_heapq.heapreplace
206
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700207 heap: object(subclass_of='&PyList_Type')
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100208 item: object
209 /
210
211Pop and return the current smallest value, and add the new item.
212
213This is more efficient than heappop() followed by heappush(), and can be
214more appropriate when using a fixed-size heap. Note that the value
215returned may be larger than item! That constrains reasonable uses of
216this routine unless written as part of a conditional replacement:
217
218 if item > heap[0]:
219 item = heapreplace(heap, item)
220[clinic start generated code]*/
221
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700222static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100223_heapq_heapreplace_impl(PyObject *module, PyObject *heap, PyObject *item)
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700224/*[clinic end generated code: output=82ea55be8fbe24b4 input=719202ac02ba10c8]*/
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700225{
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100226 return heapreplace_internal(heap, item, siftup);
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700227}
228
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100229/*[clinic input]
230_heapq.heappushpop
231
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700232 heap: object(subclass_of='&PyList_Type')
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100233 item: object
234 /
235
236Push item on the heap, then pop and return the smallest item from the heap.
237
238The combined action runs more efficiently than heappush() followed by
239a separate call to heappop().
240[clinic start generated code]*/
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000241
242static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100243_heapq_heappushpop_impl(PyObject *module, PyObject *heap, PyObject *item)
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700244/*[clinic end generated code: output=67231dc98ed5774f input=5dc701f1eb4a4aa7]*/
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000245{
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100246 PyObject *returnitem;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000247 int cmp;
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000248
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700249 if (PyList_GET_SIZE(heap) == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000250 Py_INCREF(item);
251 return item;
252 }
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000253
Pablo Galindo79f89e62020-01-23 14:07:05 +0000254 PyObject* top = PyList_GET_ITEM(heap, 0);
255 Py_INCREF(top);
256 cmp = PyObject_RichCompareBool(top, item, Py_LT);
257 Py_DECREF(top);
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700258 if (cmp < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000259 return NULL;
260 if (cmp == 0) {
261 Py_INCREF(item);
262 return item;
263 }
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000264
Raymond Hettingerb9db9e12015-05-11 19:58:56 -0700265 if (PyList_GET_SIZE(heap) == 0) {
266 PyErr_SetString(PyExc_IndexError, "index out of range");
267 return NULL;
268 }
269
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000270 returnitem = PyList_GET_ITEM(heap, 0);
271 Py_INCREF(item);
272 PyList_SET_ITEM(heap, 0, item);
Raymond Hettingera032e462015-05-11 10:32:57 -0700273 if (siftup((PyListObject *)heap, 0)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000274 Py_DECREF(returnitem);
275 return NULL;
276 }
277 return returnitem;
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000278}
279
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700280static Py_ssize_t
281keep_top_bit(Py_ssize_t n)
282{
283 int i = 0;
284
285 while (n > 1) {
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700286 n >>= 1;
Raymond Hettingerd69755d2015-05-15 17:53:52 -0700287 i++;
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700288 }
289 return n << i;
290}
291
292/* Cache friendly version of heapify()
293 -----------------------------------
294
295 Build-up a heap in O(n) time by performing siftup() operations
296 on nodes whose children are already heaps.
297
298 The simplest way is to sift the nodes in reverse order from
299 n//2-1 to 0 inclusive. The downside is that children may be
300 out of cache by the time their parent is reached.
301
302 A better way is to not wait for the children to go out of cache.
303 Once a sibling pair of child nodes have been sifted, immediately
304 sift their parent node (while the children are still in cache).
305
306 Both ways build child heaps before their parents, so both ways
307 do the exact same number of comparisons and produce exactly
308 the same heap. The only difference is that the traversal
309 order is optimized for cache efficiency.
310*/
311
312static PyObject *
313cache_friendly_heapify(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
314{
315 Py_ssize_t i, j, m, mhalf, leftmost;
316
317 m = PyList_GET_SIZE(heap) >> 1; /* index of first childless node */
318 leftmost = keep_top_bit(m + 1) - 1; /* leftmost node in row of m */
319 mhalf = m >> 1; /* parent of first childless node */
320
321 for (i = leftmost - 1 ; i >= mhalf ; i--) {
322 j = i;
323 while (1) {
324 if (siftup_func((PyListObject *)heap, j))
325 return NULL;
326 if (!(j & 1))
327 break;
328 j >>= 1;
329 }
330 }
331
332 for (i = m - 1 ; i >= leftmost ; i--) {
333 j = i;
334 while (1) {
335 if (siftup_func((PyListObject *)heap, j))
336 return NULL;
337 if (!(j & 1))
338 break;
339 j >>= 1;
340 }
341 }
342 Py_RETURN_NONE;
343}
344
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000345static PyObject *
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700346heapify_internal(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000347{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000348 Py_ssize_t i, n;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000349
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700350 /* For heaps likely to be bigger than L1 cache, we use the cache
351 friendly heapify function. For smaller heaps that fit entirely
352 in cache, we prefer the simpler algorithm with less branching.
353 */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000354 n = PyList_GET_SIZE(heap);
Raymond Hettinger63648802015-05-12 21:40:50 -0700355 if (n > 2500)
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700356 return cache_friendly_heapify(heap, siftup_func);
357
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000358 /* Transform bottom-up. The largest index there's any point to
359 looking at is the largest with a child index in-range, so must
360 have 2*i + 1 < n, or i < (n-1)/2. If n is even = 2*j, this is
361 (2*j-1)/2 = j-1/2 so j-1 is the largest, which is n//2 - 1. If
362 n is odd = 2*j+1, this is (2*j+1-1)/2 = j so j-1 is the largest,
363 and that's again n//2-1.
364 */
Raymond Hettingercfe5b6c2015-07-20 00:25:50 -0400365 for (i = (n >> 1) - 1 ; i >= 0 ; i--)
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700366 if (siftup_func((PyListObject *)heap, i))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000367 return NULL;
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700368 Py_RETURN_NONE;
369}
370
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100371/*[clinic input]
372_heapq.heapify
373
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700374 heap: object(subclass_of='&PyList_Type')
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100375 /
376
377Transform list into a heap, in-place, in O(len(heap)) time.
378[clinic start generated code]*/
379
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700380static PyObject *
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700381_heapq_heapify_impl(PyObject *module, PyObject *heap)
382/*[clinic end generated code: output=e63a636fcf83d6d0 input=53bb7a2166febb73]*/
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700383{
384 return heapify_internal(heap, siftup);
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000385}
386
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000387static int
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700388siftdown_max(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000389{
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700390 PyObject *newitem, *parent, **arr;
Raymond Hettinger90e93382014-05-03 18:45:54 -0700391 Py_ssize_t parentpos, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000392 int cmp;
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000393
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000394 assert(PyList_Check(heap));
Raymond Hettinger90e93382014-05-03 18:45:54 -0700395 size = PyList_GET_SIZE(heap);
396 if (pos >= size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000397 PyErr_SetString(PyExc_IndexError, "index out of range");
398 return -1;
399 }
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000400
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000401 /* Follow the path to the root, moving parents down until finding
402 a place newitem fits. */
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700403 arr = _PyList_ITEMS(heap);
404 newitem = arr[pos];
Raymond Hettinger90e93382014-05-03 18:45:54 -0700405 while (pos > startpos) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000406 parentpos = (pos - 1) >> 1;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700407 parent = arr[parentpos];
Pablo Galindo79f89e62020-01-23 14:07:05 +0000408 Py_INCREF(parent);
409 Py_INCREF(newitem);
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +0000410 cmp = PyObject_RichCompareBool(parent, newitem, Py_LT);
Pablo Galindo79f89e62020-01-23 14:07:05 +0000411 Py_DECREF(parent);
412 Py_DECREF(newitem);
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700413 if (cmp < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000414 return -1;
Raymond Hettinger90e93382014-05-03 18:45:54 -0700415 if (size != PyList_GET_SIZE(heap)) {
416 PyErr_SetString(PyExc_RuntimeError,
417 "list changed size during iteration");
418 return -1;
419 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000420 if (cmp == 0)
421 break;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700422 arr = _PyList_ITEMS(heap);
423 parent = arr[parentpos];
424 newitem = arr[pos];
425 arr[parentpos] = newitem;
426 arr[pos] = parent;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000427 pos = parentpos;
428 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000429 return 0;
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000430}
431
432static int
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700433siftup_max(PyListObject *heap, Py_ssize_t pos)
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000434{
Raymond Hettingerc784c6d2015-05-15 21:01:13 -0700435 Py_ssize_t startpos, endpos, childpos, limit;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700436 PyObject *tmp1, *tmp2, **arr;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000437 int cmp;
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000438
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000439 assert(PyList_Check(heap));
440 endpos = PyList_GET_SIZE(heap);
441 startpos = pos;
442 if (pos >= endpos) {
443 PyErr_SetString(PyExc_IndexError, "index out of range");
444 return -1;
445 }
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000446
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000447 /* Bubble up the smaller child until hitting a leaf. */
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700448 arr = _PyList_ITEMS(heap);
Raymond Hettingercfe5b6c2015-07-20 00:25:50 -0400449 limit = endpos >> 1; /* smallest pos that has no child */
Raymond Hettingerc9926082014-05-03 15:22:07 -0700450 while (pos < limit) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000451 /* Set childpos to index of smaller child. */
Raymond Hettingerc9926082014-05-03 15:22:07 -0700452 childpos = 2*pos + 1; /* leftmost child position */
Raymond Hettingerc784c6d2015-05-15 21:01:13 -0700453 if (childpos + 1 < endpos) {
Pablo Galindo79f89e62020-01-23 14:07:05 +0000454 PyObject* a = arr[childpos + 1];
455 PyObject* b = arr[childpos];
456 Py_INCREF(a);
457 Py_INCREF(b);
458 cmp = PyObject_RichCompareBool(a, b, Py_LT);
459 Py_DECREF(a);
460 Py_DECREF(b);
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700461 if (cmp < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000462 return -1;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700463 childpos += ((unsigned)cmp ^ 1); /* increment when cmp==0 */
Raymond Hettinger2300bf22015-12-07 20:45:16 -0800464 arr = _PyList_ITEMS(heap); /* arr may have changed */
Raymond Hettinger871620d2014-05-03 18:36:48 -0700465 if (endpos != PyList_GET_SIZE(heap)) {
466 PyErr_SetString(PyExc_RuntimeError,
467 "list changed size during iteration");
468 return -1;
469 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000470 }
471 /* Move the smaller child up. */
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700472 tmp1 = arr[childpos];
473 tmp2 = arr[pos];
474 arr[childpos] = tmp2;
475 arr[pos] = tmp1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000476 pos = childpos;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000477 }
Raymond Hettinger871620d2014-05-03 18:36:48 -0700478 /* Bubble it up to its final resting place (by sifting its parents down). */
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700479 return siftdown_max(heap, startpos, pos);
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000480}
481
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100482
483/*[clinic input]
484_heapq._heappop_max
485
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700486 heap: object(subclass_of='&PyList_Type')
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100487 /
488
489Maxheap variant of heappop.
490[clinic start generated code]*/
491
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000492static PyObject *
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700493_heapq__heappop_max_impl(PyObject *module, PyObject *heap)
494/*[clinic end generated code: output=9e77aadd4e6a8760 input=362c06e1c7484793]*/
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000495{
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700496 return heappop_internal(heap, siftup_max);
497}
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000498
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100499/*[clinic input]
500_heapq._heapreplace_max
501
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700502 heap: object(subclass_of='&PyList_Type')
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100503 item: object
504 /
505
506Maxheap variant of heapreplace.
507[clinic start generated code]*/
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000508
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700509static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100510_heapq__heapreplace_max_impl(PyObject *module, PyObject *heap,
511 PyObject *item)
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700512/*[clinic end generated code: output=8ad7545e4a5e8adb input=f2dd27cbadb948d7]*/
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700513{
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100514 return heapreplace_internal(heap, item, siftup_max);
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000515}
516
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100517/*[clinic input]
518_heapq._heapify_max
519
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700520 heap: object(subclass_of='&PyList_Type')
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100521 /
522
523Maxheap variant of heapify.
524[clinic start generated code]*/
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000525
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700526static PyObject *
Raymond Hettinger0226f3e2020-05-22 07:28:57 -0700527_heapq__heapify_max_impl(PyObject *module, PyObject *heap)
528/*[clinic end generated code: output=2cb028beb4a8b65e input=c1f765ee69f124b8]*/
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700529{
530 return heapify_internal(heap, siftup_max);
531}
532
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000533static PyMethodDef heapq_methods[] = {
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100534 _HEAPQ_HEAPPUSH_METHODDEF
535 _HEAPQ_HEAPPUSHPOP_METHODDEF
536 _HEAPQ_HEAPPOP_METHODDEF
537 _HEAPQ_HEAPREPLACE_METHODDEF
538 _HEAPQ_HEAPIFY_METHODDEF
539 _HEAPQ__HEAPPOP_MAX_METHODDEF
540 _HEAPQ__HEAPIFY_MAX_METHODDEF
541 _HEAPQ__HEAPREPLACE_MAX_METHODDEF
542 {NULL, NULL} /* sentinel */
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000543};
544
545PyDoc_STRVAR(module_doc,
546"Heap queue algorithm (a.k.a. priority queue).\n\
547\n\
548Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for\n\
549all k, counting elements from 0. For the sake of comparison,\n\
550non-existing elements are considered to be infinite. The interesting\n\
551property of a heap is that a[0] is always its smallest element.\n\
552\n\
553Usage:\n\
554\n\
555heap = [] # creates an empty heap\n\
556heappush(heap, item) # pushes a new item on the heap\n\
557item = heappop(heap) # pops the smallest item from the heap\n\
558item = heap[0] # smallest item on the heap without popping it\n\
559heapify(x) # transforms list into a heap, in-place, in linear time\n\
560item = heapreplace(heap, item) # pops and returns smallest item, and adds\n\
561 # new item; the heap size is unchanged\n\
562\n\
563Our API differs from textbook heap algorithms as follows:\n\
564\n\
565- We use 0-based indexing. This makes the relationship between the\n\
566 index for a node and the indexes for its children slightly less\n\
567 obvious, but is more suitable since Python uses 0-based indexing.\n\
568\n\
569- Our heappop() method returns the smallest item, not the largest.\n\
570\n\
571These two make it possible to view the heap as a regular Python list\n\
572without surprises: heap[0] is the smallest item, and heap.sort()\n\
573maintains the heap invariant!\n");
574
575
576PyDoc_STRVAR(__about__,
577"Heap queues\n\
578\n\
Neal Norwitzc1786ea2007-08-23 23:58:43 +0000579[explanation by Fran\xc3\xa7ois Pinard]\n\
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000580\n\
581Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for\n\
582all k, counting elements from 0. For the sake of comparison,\n\
583non-existing elements are considered to be infinite. The interesting\n\
584property of a heap is that a[0] is always its smallest element.\n"
585"\n\
586The strange invariant above is meant to be an efficient memory\n\
587representation for a tournament. The numbers below are `k', not a[k]:\n\
588\n\
589 0\n\
590\n\
591 1 2\n\
592\n\
593 3 4 5 6\n\
594\n\
595 7 8 9 10 11 12 13 14\n\
596\n\
597 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30\n\
598\n\
599\n\
600In the tree above, each cell `k' is topping `2*k+1' and `2*k+2'. In\n\
Martin Panter6245cb32016-04-15 02:14:19 +0000601a usual binary tournament we see in sports, each cell is the winner\n\
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000602over the two cells it tops, and we can trace the winner down the tree\n\
603to see all opponents s/he had. However, in many computer applications\n\
604of such tournaments, we do not need to trace the history of a winner.\n\
605To be more memory efficient, when a winner is promoted, we try to\n\
606replace it by something else at a lower level, and the rule becomes\n\
607that a cell and the two cells it tops contain three different items,\n\
608but the top cell \"wins\" over the two topped cells.\n"
609"\n\
610If this heap invariant is protected at all time, index 0 is clearly\n\
611the overall winner. The simplest algorithmic way to remove it and\n\
612find the \"next\" winner is to move some loser (let's say cell 30 in the\n\
613diagram above) into the 0 position, and then percolate this new 0 down\n\
614the tree, exchanging values, until the invariant is re-established.\n\
615This is clearly logarithmic on the total number of items in the tree.\n\
616By iterating over all items, you get an O(n ln n) sort.\n"
617"\n\
618A nice feature of this sort is that you can efficiently insert new\n\
619items while the sort is going on, provided that the inserted items are\n\
620not \"better\" than the last 0'th element you extracted. This is\n\
621especially useful in simulation contexts, where the tree holds all\n\
622incoming events, and the \"win\" condition means the smallest scheduled\n\
623time. When an event schedule other events for execution, they are\n\
624scheduled into the future, so they can easily go into the heap. So, a\n\
625heap is a good structure for implementing schedulers (this is what I\n\
626used for my MIDI sequencer :-).\n"
627"\n\
628Various structures for implementing schedulers have been extensively\n\
629studied, and heaps are good for this, as they are reasonably speedy,\n\
630the speed is almost constant, and the worst case is not much different\n\
631than the average case. However, there are other representations which\n\
632are more efficient overall, yet the worst cases might be terrible.\n"
633"\n\
634Heaps are also very useful in big disk sorts. You most probably all\n\
635know that a big sort implies producing \"runs\" (which are pre-sorted\n\
636sequences, which size is usually related to the amount of CPU memory),\n\
637followed by a merging passes for these runs, which merging is often\n\
638very cleverly organised[1]. It is very important that the initial\n\
639sort produces the longest runs possible. Tournaments are a good way\n\
640to that. If, using all the memory available to hold a tournament, you\n\
641replace and percolate items that happen to fit the current run, you'll\n\
642produce runs which are twice the size of the memory for random input,\n\
643and much better for input fuzzily ordered.\n"
644"\n\
645Moreover, if you output the 0'th item on disk and get an input which\n\
646may not fit in the current tournament (because the value \"wins\" over\n\
647the last output value), it cannot fit in the heap, so the size of the\n\
648heap decreases. The freed memory could be cleverly reused immediately\n\
649for progressively building a second heap, which grows at exactly the\n\
650same rate the first heap is melting. When the first heap completely\n\
651vanishes, you switch heaps and start a new run. Clever and quite\n\
652effective!\n\
653\n\
654In a word, heaps are useful memory structures to know. I use them in\n\
655a few applications, and I think it is good to keep a `heap' module\n\
656around. :-)\n"
657"\n\
658--------------------\n\
659[1] The disk balancing algorithms which are current, nowadays, are\n\
660more annoying than clever, and this is a consequence of the seeking\n\
661capabilities of the disks. On devices which cannot seek, like big\n\
662tape drives, the story was quite different, and one had to be very\n\
663clever to ensure (far in advance) that each tape movement will be the\n\
664most effective possible (that is, will best participate at\n\
665\"progressing\" the merge). Some tapes were even able to read\n\
666backwards, and this was also used to avoid the rewinding time.\n\
667Believe me, real good tape sorts were quite spectacular to watch!\n\
668From all times, sorting has always been a Great Art! :-)\n");
669
Martin v. Löwis1a214512008-06-11 05:26:20 +0000670
Dong-hee Na4657a8a2020-03-18 23:29:34 +0900671static int
672heapq_exec(PyObject *m)
673{
674 PyObject *about = PyUnicode_FromString(__about__);
675 if (PyModule_AddObject(m, "__about__", about) < 0) {
676 Py_DECREF(about);
677 return -1;
678 }
679 return 0;
680}
681
682static struct PyModuleDef_Slot heapq_slots[] = {
683 {Py_mod_exec, heapq_exec},
684 {0, NULL}
685};
686
Martin v. Löwis1a214512008-06-11 05:26:20 +0000687static struct PyModuleDef _heapqmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000688 PyModuleDef_HEAD_INIT,
689 "_heapq",
690 module_doc,
Dong-hee Na4657a8a2020-03-18 23:29:34 +0900691 0,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000692 heapq_methods,
Dong-hee Na4657a8a2020-03-18 23:29:34 +0900693 heapq_slots,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000694 NULL,
695 NULL,
696 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000697};
698
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000699PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000700PyInit__heapq(void)
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000701{
Dong-hee Na4657a8a2020-03-18 23:29:34 +0900702 return PyModuleDef_Init(&_heapqmodule);
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000703}