blob: a84cade3aaa16a5c40d054a174699140c9ba79ff [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];
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +000039 cmp = PyObject_RichCompareBool(newitem, parent, Py_LT);
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070040 if (cmp < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000041 return -1;
Antoine Pitrou44d52142013-03-04 20:30:01 +010042 if (size != PyList_GET_SIZE(heap)) {
Antoine Pitrou44d52142013-03-04 20:30:01 +010043 PyErr_SetString(PyExc_RuntimeError,
44 "list changed size during iteration");
45 return -1;
46 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000047 if (cmp == 0)
48 break;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070049 arr = _PyList_ITEMS(heap);
50 parent = arr[parentpos];
51 newitem = arr[pos];
52 arr[parentpos] = newitem;
53 arr[pos] = parent;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000054 pos = parentpos;
55 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000056 return 0;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000057}
58
59static int
Raymond Hettinger48f68d02014-06-14 16:43:35 -070060siftup(PyListObject *heap, Py_ssize_t pos)
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000061{
Raymond Hettingerc784c6d2015-05-15 21:01:13 -070062 Py_ssize_t startpos, endpos, childpos, limit;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070063 PyObject *tmp1, *tmp2, **arr;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000064 int cmp;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000065
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000066 assert(PyList_Check(heap));
Raymond Hettinger871620d2014-05-03 18:36:48 -070067 endpos = PyList_GET_SIZE(heap);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000068 startpos = pos;
69 if (pos >= endpos) {
70 PyErr_SetString(PyExc_IndexError, "index out of range");
71 return -1;
72 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +000073
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000074 /* Bubble up the smaller child until hitting a leaf. */
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070075 arr = _PyList_ITEMS(heap);
Raymond Hettingercfe5b6c2015-07-20 00:25:50 -040076 limit = endpos >> 1; /* smallest pos that has no child */
Raymond Hettingerc9926082014-05-03 15:22:07 -070077 while (pos < limit) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000078 /* Set childpos to index of smaller child. */
Raymond Hettingerc9926082014-05-03 15:22:07 -070079 childpos = 2*pos + 1; /* leftmost child position */
Raymond Hettingerc784c6d2015-05-15 21:01:13 -070080 if (childpos + 1 < endpos) {
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +000081 cmp = PyObject_RichCompareBool(
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070082 arr[childpos],
83 arr[childpos + 1],
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +000084 Py_LT);
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070085 if (cmp < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000086 return -1;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070087 childpos += ((unsigned)cmp ^ 1); /* increment when cmp==0 */
Raymond Hettinger2300bf22015-12-07 20:45:16 -080088 arr = _PyList_ITEMS(heap); /* arr may have changed */
Raymond Hettinger871620d2014-05-03 18:36:48 -070089 if (endpos != PyList_GET_SIZE(heap)) {
90 PyErr_SetString(PyExc_RuntimeError,
91 "list changed size during iteration");
92 return -1;
93 }
Antoine Pitrou44d52142013-03-04 20:30:01 +010094 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000095 /* Move the smaller child up. */
Raymond Hettinger5cbd8332015-05-22 00:41:57 -070096 tmp1 = arr[childpos];
97 tmp2 = arr[pos];
98 arr[childpos] = tmp2;
99 arr[pos] = tmp1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000100 pos = childpos;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000101 }
Raymond Hettinger871620d2014-05-03 18:36:48 -0700102 /* Bubble it up to its final resting place (by sifting its parents down). */
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700103 return siftdown(heap, startpos, pos);
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000104}
105
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100106/*[clinic input]
107_heapq.heappush
108
109 heap: object
110 item: object
111 /
112
113Push item onto heap, maintaining the heap invariant.
114[clinic start generated code]*/
115
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000116static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100117_heapq_heappush_impl(PyObject *module, PyObject *heap, PyObject *item)
118/*[clinic end generated code: output=912c094f47663935 input=7913545cb5118842]*/
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000119{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000120 if (!PyList_Check(heap)) {
121 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
122 return NULL;
123 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000124
Raymond Hettingera032e462015-05-11 10:32:57 -0700125 if (PyList_Append(heap, item))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000126 return NULL;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000127
Raymond Hettingera032e462015-05-11 10:32:57 -0700128 if (siftdown((PyListObject *)heap, 0, PyList_GET_SIZE(heap)-1))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000129 return NULL;
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700130 Py_RETURN_NONE;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000131}
132
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000133static PyObject *
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700134heappop_internal(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000135{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000136 PyObject *lastelt, *returnitem;
137 Py_ssize_t n;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000138
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000139 if (!PyList_Check(heap)) {
140 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
141 return NULL;
142 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000143
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700144 /* raises IndexError if the heap is empty */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000145 n = PyList_GET_SIZE(heap);
146 if (n == 0) {
147 PyErr_SetString(PyExc_IndexError, "index out of range");
148 return NULL;
149 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000150
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000151 lastelt = PyList_GET_ITEM(heap, n-1) ;
152 Py_INCREF(lastelt);
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700153 if (PyList_SetSlice(heap, n-1, n, NULL)) {
Victor Stinner764a46d2013-07-17 21:50:21 +0200154 Py_DECREF(lastelt);
155 return NULL;
156 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000157 n--;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000158
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000159 if (!n)
160 return lastelt;
161 returnitem = PyList_GET_ITEM(heap, 0);
162 PyList_SET_ITEM(heap, 0, lastelt);
Raymond Hettingera032e462015-05-11 10:32:57 -0700163 if (siftup_func((PyListObject *)heap, 0)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000164 Py_DECREF(returnitem);
165 return NULL;
166 }
167 return returnitem;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000168}
169
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100170/*[clinic input]
171_heapq.heappop
172
173 heap: object
174 /
175
176Pop the smallest item off the heap, maintaining the heap invariant.
177[clinic start generated code]*/
178
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700179static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100180_heapq_heappop(PyObject *module, PyObject *heap)
181/*[clinic end generated code: output=e1bbbc9866bce179 input=9bd36317b806033d]*/
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700182{
183 return heappop_internal(heap, siftup);
184}
185
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000186static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100187heapreplace_internal(PyObject *heap, PyObject *item, int siftup_func(PyListObject *, Py_ssize_t))
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000188{
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100189 PyObject *returnitem;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000190
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000191 if (!PyList_Check(heap)) {
192 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
193 return NULL;
194 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000195
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700196 if (PyList_GET_SIZE(heap) == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000197 PyErr_SetString(PyExc_IndexError, "index out of range");
198 return NULL;
199 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000200
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000201 returnitem = PyList_GET_ITEM(heap, 0);
202 Py_INCREF(item);
203 PyList_SET_ITEM(heap, 0, item);
Raymond Hettingera032e462015-05-11 10:32:57 -0700204 if (siftup_func((PyListObject *)heap, 0)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000205 Py_DECREF(returnitem);
206 return NULL;
207 }
208 return returnitem;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000209}
210
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100211
212/*[clinic input]
213_heapq.heapreplace
214
215 heap: object
216 item: object
217 /
218
219Pop and return the current smallest value, and add the new item.
220
221This is more efficient than heappop() followed by heappush(), and can be
222more appropriate when using a fixed-size heap. Note that the value
223returned may be larger than item! That constrains reasonable uses of
224this routine unless written as part of a conditional replacement:
225
226 if item > heap[0]:
227 item = heapreplace(heap, item)
228[clinic start generated code]*/
229
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700230static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100231_heapq_heapreplace_impl(PyObject *module, PyObject *heap, PyObject *item)
232/*[clinic end generated code: output=82ea55be8fbe24b4 input=e57ae8f4ecfc88e3]*/
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700233{
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100234 return heapreplace_internal(heap, item, siftup);
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700235}
236
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100237/*[clinic input]
238_heapq.heappushpop
239
240 heap: object
241 item: object
242 /
243
244Push item on the heap, then pop and return the smallest item from the heap.
245
246The combined action runs more efficiently than heappush() followed by
247a separate call to heappop().
248[clinic start generated code]*/
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000249
250static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100251_heapq_heappushpop_impl(PyObject *module, PyObject *heap, PyObject *item)
252/*[clinic end generated code: output=67231dc98ed5774f input=eb48c90ba77b2214]*/
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000253{
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100254 PyObject *returnitem;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000255 int cmp;
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000256
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000257 if (!PyList_Check(heap)) {
258 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
259 return NULL;
260 }
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000261
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700262 if (PyList_GET_SIZE(heap) == 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000263 Py_INCREF(item);
264 return item;
265 }
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000266
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +0000267 cmp = PyObject_RichCompareBool(PyList_GET_ITEM(heap, 0), item, Py_LT);
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700268 if (cmp < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000269 return NULL;
270 if (cmp == 0) {
271 Py_INCREF(item);
272 return item;
273 }
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000274
Raymond Hettingerb9db9e12015-05-11 19:58:56 -0700275 if (PyList_GET_SIZE(heap) == 0) {
276 PyErr_SetString(PyExc_IndexError, "index out of range");
277 return NULL;
278 }
279
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000280 returnitem = PyList_GET_ITEM(heap, 0);
281 Py_INCREF(item);
282 PyList_SET_ITEM(heap, 0, item);
Raymond Hettingera032e462015-05-11 10:32:57 -0700283 if (siftup((PyListObject *)heap, 0)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000284 Py_DECREF(returnitem);
285 return NULL;
286 }
287 return returnitem;
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000288}
289
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700290static Py_ssize_t
291keep_top_bit(Py_ssize_t n)
292{
293 int i = 0;
294
295 while (n > 1) {
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700296 n >>= 1;
Raymond Hettingerd69755d2015-05-15 17:53:52 -0700297 i++;
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700298 }
299 return n << i;
300}
301
302/* Cache friendly version of heapify()
303 -----------------------------------
304
305 Build-up a heap in O(n) time by performing siftup() operations
306 on nodes whose children are already heaps.
307
308 The simplest way is to sift the nodes in reverse order from
309 n//2-1 to 0 inclusive. The downside is that children may be
310 out of cache by the time their parent is reached.
311
312 A better way is to not wait for the children to go out of cache.
313 Once a sibling pair of child nodes have been sifted, immediately
314 sift their parent node (while the children are still in cache).
315
316 Both ways build child heaps before their parents, so both ways
317 do the exact same number of comparisons and produce exactly
318 the same heap. The only difference is that the traversal
319 order is optimized for cache efficiency.
320*/
321
322static PyObject *
323cache_friendly_heapify(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
324{
325 Py_ssize_t i, j, m, mhalf, leftmost;
326
327 m = PyList_GET_SIZE(heap) >> 1; /* index of first childless node */
328 leftmost = keep_top_bit(m + 1) - 1; /* leftmost node in row of m */
329 mhalf = m >> 1; /* parent of first childless node */
330
331 for (i = leftmost - 1 ; i >= mhalf ; i--) {
332 j = i;
333 while (1) {
334 if (siftup_func((PyListObject *)heap, j))
335 return NULL;
336 if (!(j & 1))
337 break;
338 j >>= 1;
339 }
340 }
341
342 for (i = m - 1 ; i >= leftmost ; i--) {
343 j = i;
344 while (1) {
345 if (siftup_func((PyListObject *)heap, j))
346 return NULL;
347 if (!(j & 1))
348 break;
349 j >>= 1;
350 }
351 }
352 Py_RETURN_NONE;
353}
354
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000355static PyObject *
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700356heapify_internal(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000357{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000358 Py_ssize_t i, n;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000359
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000360 if (!PyList_Check(heap)) {
361 PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
362 return NULL;
363 }
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000364
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700365 /* For heaps likely to be bigger than L1 cache, we use the cache
366 friendly heapify function. For smaller heaps that fit entirely
367 in cache, we prefer the simpler algorithm with less branching.
368 */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000369 n = PyList_GET_SIZE(heap);
Raymond Hettinger63648802015-05-12 21:40:50 -0700370 if (n > 2500)
Raymond Hettingerbc33e572015-05-11 10:19:03 -0700371 return cache_friendly_heapify(heap, siftup_func);
372
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000373 /* Transform bottom-up. The largest index there's any point to
374 looking at is the largest with a child index in-range, so must
375 have 2*i + 1 < n, or i < (n-1)/2. If n is even = 2*j, this is
376 (2*j-1)/2 = j-1/2 so j-1 is the largest, which is n//2 - 1. If
377 n is odd = 2*j+1, this is (2*j+1-1)/2 = j so j-1 is the largest,
378 and that's again n//2-1.
379 */
Raymond Hettingercfe5b6c2015-07-20 00:25:50 -0400380 for (i = (n >> 1) - 1 ; i >= 0 ; i--)
Raymond Hettinger99bf9a22015-05-11 19:25:32 -0700381 if (siftup_func((PyListObject *)heap, i))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000382 return NULL;
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700383 Py_RETURN_NONE;
384}
385
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100386/*[clinic input]
387_heapq.heapify
388
389 heap: object
390 /
391
392Transform list into a heap, in-place, in O(len(heap)) time.
393[clinic start generated code]*/
394
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700395static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100396_heapq_heapify(PyObject *module, PyObject *heap)
397/*[clinic end generated code: output=11483f23627c4616 input=872c87504b8de970]*/
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700398{
399 return heapify_internal(heap, siftup);
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000400}
401
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000402static int
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700403siftdown_max(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000404{
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700405 PyObject *newitem, *parent, **arr;
Raymond Hettinger90e93382014-05-03 18:45:54 -0700406 Py_ssize_t parentpos, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000407 int cmp;
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000408
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000409 assert(PyList_Check(heap));
Raymond Hettinger90e93382014-05-03 18:45:54 -0700410 size = PyList_GET_SIZE(heap);
411 if (pos >= size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000412 PyErr_SetString(PyExc_IndexError, "index out of range");
413 return -1;
414 }
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000415
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000416 /* Follow the path to the root, moving parents down until finding
417 a place newitem fits. */
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700418 arr = _PyList_ITEMS(heap);
419 newitem = arr[pos];
Raymond Hettinger90e93382014-05-03 18:45:54 -0700420 while (pos > startpos) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000421 parentpos = (pos - 1) >> 1;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700422 parent = arr[parentpos];
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +0000423 cmp = PyObject_RichCompareBool(parent, newitem, Py_LT);
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700424 if (cmp < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000425 return -1;
Raymond Hettinger90e93382014-05-03 18:45:54 -0700426 if (size != PyList_GET_SIZE(heap)) {
427 PyErr_SetString(PyExc_RuntimeError,
428 "list changed size during iteration");
429 return -1;
430 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000431 if (cmp == 0)
432 break;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700433 arr = _PyList_ITEMS(heap);
434 parent = arr[parentpos];
435 newitem = arr[pos];
436 arr[parentpos] = newitem;
437 arr[pos] = parent;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000438 pos = parentpos;
439 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000440 return 0;
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000441}
442
443static int
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700444siftup_max(PyListObject *heap, Py_ssize_t pos)
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000445{
Raymond Hettingerc784c6d2015-05-15 21:01:13 -0700446 Py_ssize_t startpos, endpos, childpos, limit;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700447 PyObject *tmp1, *tmp2, **arr;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000448 int cmp;
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000449
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000450 assert(PyList_Check(heap));
451 endpos = PyList_GET_SIZE(heap);
452 startpos = pos;
453 if (pos >= endpos) {
454 PyErr_SetString(PyExc_IndexError, "index out of range");
455 return -1;
456 }
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000457
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000458 /* Bubble up the smaller child until hitting a leaf. */
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700459 arr = _PyList_ITEMS(heap);
Raymond Hettingercfe5b6c2015-07-20 00:25:50 -0400460 limit = endpos >> 1; /* smallest pos that has no child */
Raymond Hettingerc9926082014-05-03 15:22:07 -0700461 while (pos < limit) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000462 /* Set childpos to index of smaller child. */
Raymond Hettingerc9926082014-05-03 15:22:07 -0700463 childpos = 2*pos + 1; /* leftmost child position */
Raymond Hettingerc784c6d2015-05-15 21:01:13 -0700464 if (childpos + 1 < endpos) {
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +0000465 cmp = PyObject_RichCompareBool(
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700466 arr[childpos + 1],
467 arr[childpos],
Raymond Hettingerdb6b62e2010-09-05 05:26:10 +0000468 Py_LT);
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700469 if (cmp < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000470 return -1;
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700471 childpos += ((unsigned)cmp ^ 1); /* increment when cmp==0 */
Raymond Hettinger2300bf22015-12-07 20:45:16 -0800472 arr = _PyList_ITEMS(heap); /* arr may have changed */
Raymond Hettinger871620d2014-05-03 18:36:48 -0700473 if (endpos != PyList_GET_SIZE(heap)) {
474 PyErr_SetString(PyExc_RuntimeError,
475 "list changed size during iteration");
476 return -1;
477 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000478 }
479 /* Move the smaller child up. */
Raymond Hettinger5cbd8332015-05-22 00:41:57 -0700480 tmp1 = arr[childpos];
481 tmp2 = arr[pos];
482 arr[childpos] = tmp2;
483 arr[pos] = tmp1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000484 pos = childpos;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000485 }
Raymond Hettinger871620d2014-05-03 18:36:48 -0700486 /* Bubble it up to its final resting place (by sifting its parents down). */
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700487 return siftdown_max(heap, startpos, pos);
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000488}
489
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100490
491/*[clinic input]
492_heapq._heappop_max
493
494 heap: object
495 /
496
497Maxheap variant of heappop.
498[clinic start generated code]*/
499
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000500static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100501_heapq__heappop_max(PyObject *module, PyObject *heap)
502/*[clinic end generated code: output=acd30acf6384b13c input=62ede3ba9117f541]*/
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000503{
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700504 return heappop_internal(heap, siftup_max);
505}
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000506
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100507/*[clinic input]
508_heapq._heapreplace_max
509
510 heap: object
511 item: object
512 /
513
514Maxheap variant of heapreplace.
515[clinic start generated code]*/
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000516
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700517static PyObject *
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100518_heapq__heapreplace_max_impl(PyObject *module, PyObject *heap,
519 PyObject *item)
520/*[clinic end generated code: output=8ad7545e4a5e8adb input=6d8f25131e0f0e5f]*/
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700521{
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100522 return heapreplace_internal(heap, item, siftup_max);
Raymond Hettinger2e3dfaf2004-06-13 05:26:33 +0000523}
524
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100525/*[clinic input]
526_heapq._heapify_max
527
528 heap: object
529 /
530
531Maxheap variant of heapify.
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__heapify_max(PyObject *module, PyObject *heap)
536/*[clinic end generated code: output=1c6bb6b60d6a2133 input=cdfcc6835b14110d]*/
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700537{
538 return heapify_internal(heap, siftup_max);
539}
540
Raymond Hettinger48f68d02014-06-14 16:43:35 -0700541
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000542static PyMethodDef heapq_methods[] = {
Pablo Galindoe2f48bf2018-09-28 20:39:43 +0100543 _HEAPQ_HEAPPUSH_METHODDEF
544 _HEAPQ_HEAPPUSHPOP_METHODDEF
545 _HEAPQ_HEAPPOP_METHODDEF
546 _HEAPQ_HEAPREPLACE_METHODDEF
547 _HEAPQ_HEAPIFY_METHODDEF
548 _HEAPQ__HEAPPOP_MAX_METHODDEF
549 _HEAPQ__HEAPIFY_MAX_METHODDEF
550 _HEAPQ__HEAPREPLACE_MAX_METHODDEF
551 {NULL, NULL} /* sentinel */
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000552};
553
554PyDoc_STRVAR(module_doc,
555"Heap queue algorithm (a.k.a. priority queue).\n\
556\n\
557Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for\n\
558all k, counting elements from 0. For the sake of comparison,\n\
559non-existing elements are considered to be infinite. The interesting\n\
560property of a heap is that a[0] is always its smallest element.\n\
561\n\
562Usage:\n\
563\n\
564heap = [] # creates an empty heap\n\
565heappush(heap, item) # pushes a new item on the heap\n\
566item = heappop(heap) # pops the smallest item from the heap\n\
567item = heap[0] # smallest item on the heap without popping it\n\
568heapify(x) # transforms list into a heap, in-place, in linear time\n\
569item = heapreplace(heap, item) # pops and returns smallest item, and adds\n\
570 # new item; the heap size is unchanged\n\
571\n\
572Our API differs from textbook heap algorithms as follows:\n\
573\n\
574- We use 0-based indexing. This makes the relationship between the\n\
575 index for a node and the indexes for its children slightly less\n\
576 obvious, but is more suitable since Python uses 0-based indexing.\n\
577\n\
578- Our heappop() method returns the smallest item, not the largest.\n\
579\n\
580These two make it possible to view the heap as a regular Python list\n\
581without surprises: heap[0] is the smallest item, and heap.sort()\n\
582maintains the heap invariant!\n");
583
584
585PyDoc_STRVAR(__about__,
586"Heap queues\n\
587\n\
Neal Norwitzc1786ea2007-08-23 23:58:43 +0000588[explanation by Fran\xc3\xa7ois Pinard]\n\
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000589\n\
590Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for\n\
591all k, counting elements from 0. For the sake of comparison,\n\
592non-existing elements are considered to be infinite. The interesting\n\
593property of a heap is that a[0] is always its smallest element.\n"
594"\n\
595The strange invariant above is meant to be an efficient memory\n\
596representation for a tournament. The numbers below are `k', not a[k]:\n\
597\n\
598 0\n\
599\n\
600 1 2\n\
601\n\
602 3 4 5 6\n\
603\n\
604 7 8 9 10 11 12 13 14\n\
605\n\
606 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30\n\
607\n\
608\n\
609In the tree above, each cell `k' is topping `2*k+1' and `2*k+2'. In\n\
Martin Panter6245cb32016-04-15 02:14:19 +0000610a usual binary tournament we see in sports, each cell is the winner\n\
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000611over the two cells it tops, and we can trace the winner down the tree\n\
612to see all opponents s/he had. However, in many computer applications\n\
613of such tournaments, we do not need to trace the history of a winner.\n\
614To be more memory efficient, when a winner is promoted, we try to\n\
615replace it by something else at a lower level, and the rule becomes\n\
616that a cell and the two cells it tops contain three different items,\n\
617but the top cell \"wins\" over the two topped cells.\n"
618"\n\
619If this heap invariant is protected at all time, index 0 is clearly\n\
620the overall winner. The simplest algorithmic way to remove it and\n\
621find the \"next\" winner is to move some loser (let's say cell 30 in the\n\
622diagram above) into the 0 position, and then percolate this new 0 down\n\
623the tree, exchanging values, until the invariant is re-established.\n\
624This is clearly logarithmic on the total number of items in the tree.\n\
625By iterating over all items, you get an O(n ln n) sort.\n"
626"\n\
627A nice feature of this sort is that you can efficiently insert new\n\
628items while the sort is going on, provided that the inserted items are\n\
629not \"better\" than the last 0'th element you extracted. This is\n\
630especially useful in simulation contexts, where the tree holds all\n\
631incoming events, and the \"win\" condition means the smallest scheduled\n\
632time. When an event schedule other events for execution, they are\n\
633scheduled into the future, so they can easily go into the heap. So, a\n\
634heap is a good structure for implementing schedulers (this is what I\n\
635used for my MIDI sequencer :-).\n"
636"\n\
637Various structures for implementing schedulers have been extensively\n\
638studied, and heaps are good for this, as they are reasonably speedy,\n\
639the speed is almost constant, and the worst case is not much different\n\
640than the average case. However, there are other representations which\n\
641are more efficient overall, yet the worst cases might be terrible.\n"
642"\n\
643Heaps are also very useful in big disk sorts. You most probably all\n\
644know that a big sort implies producing \"runs\" (which are pre-sorted\n\
645sequences, which size is usually related to the amount of CPU memory),\n\
646followed by a merging passes for these runs, which merging is often\n\
647very cleverly organised[1]. It is very important that the initial\n\
648sort produces the longest runs possible. Tournaments are a good way\n\
649to that. If, using all the memory available to hold a tournament, you\n\
650replace and percolate items that happen to fit the current run, you'll\n\
651produce runs which are twice the size of the memory for random input,\n\
652and much better for input fuzzily ordered.\n"
653"\n\
654Moreover, if you output the 0'th item on disk and get an input which\n\
655may not fit in the current tournament (because the value \"wins\" over\n\
656the last output value), it cannot fit in the heap, so the size of the\n\
657heap decreases. The freed memory could be cleverly reused immediately\n\
658for progressively building a second heap, which grows at exactly the\n\
659same rate the first heap is melting. When the first heap completely\n\
660vanishes, you switch heaps and start a new run. Clever and quite\n\
661effective!\n\
662\n\
663In a word, heaps are useful memory structures to know. I use them in\n\
664a few applications, and I think it is good to keep a `heap' module\n\
665around. :-)\n"
666"\n\
667--------------------\n\
668[1] The disk balancing algorithms which are current, nowadays, are\n\
669more annoying than clever, and this is a consequence of the seeking\n\
670capabilities of the disks. On devices which cannot seek, like big\n\
671tape drives, the story was quite different, and one had to be very\n\
672clever to ensure (far in advance) that each tape movement will be the\n\
673most effective possible (that is, will best participate at\n\
674\"progressing\" the merge). Some tapes were even able to read\n\
675backwards, and this was also used to avoid the rewinding time.\n\
676Believe me, real good tape sorts were quite spectacular to watch!\n\
677From all times, sorting has always been a Great Art! :-)\n");
678
Martin v. Löwis1a214512008-06-11 05:26:20 +0000679
680static struct PyModuleDef _heapqmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000681 PyModuleDef_HEAD_INIT,
682 "_heapq",
683 module_doc,
684 -1,
685 heapq_methods,
686 NULL,
687 NULL,
688 NULL,
689 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000690};
691
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000692PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000693PyInit__heapq(void)
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000694{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000695 PyObject *m, *about;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000696
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000697 m = PyModule_Create(&_heapqmodule);
698 if (m == NULL)
699 return NULL;
700 about = PyUnicode_DecodeUTF8(__about__, strlen(__about__), NULL);
701 PyModule_AddObject(m, "__about__", about);
702 return m;
Raymond Hettingerc46cb2a2004-04-19 19:06:21 +0000703}
704