• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Drop in replacement for heapq.py
2 
3 C implementation derived directly from heapq.py in Py2.3
4 which was written by Kevin O'Connor, augmented by Tim Peters,
5 annotated by François Pinard, and converted to C by Raymond Hettinger.
6 
7 */
8 
9 #include "Python.h"
10 
11 #include "clinic/_heapqmodule.c.h"
12 
13 /*[clinic input]
14 module _heapq
15 [clinic start generated code]*/
16 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=d7cca0a2e4c0ceb3]*/
17 
18 static int
siftdown(PyListObject * heap,Py_ssize_t startpos,Py_ssize_t pos)19 siftdown(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
20 {
21     PyObject *newitem, *parent, **arr;
22     Py_ssize_t parentpos, size;
23     int cmp;
24 
25     assert(PyList_Check(heap));
26     size = PyList_GET_SIZE(heap);
27     if (pos >= size) {
28         PyErr_SetString(PyExc_IndexError, "index out of range");
29         return -1;
30     }
31 
32     /* Follow the path to the root, moving parents down until finding
33        a place newitem fits. */
34     arr = _PyList_ITEMS(heap);
35     newitem = arr[pos];
36     while (pos > startpos) {
37         parentpos = (pos - 1) >> 1;
38         parent = arr[parentpos];
39         cmp = PyObject_RichCompareBool(newitem, parent, Py_LT);
40         if (cmp < 0)
41             return -1;
42         if (size != PyList_GET_SIZE(heap)) {
43             PyErr_SetString(PyExc_RuntimeError,
44                             "list changed size during iteration");
45             return -1;
46         }
47         if (cmp == 0)
48             break;
49         arr = _PyList_ITEMS(heap);
50         parent = arr[parentpos];
51         newitem = arr[pos];
52         arr[parentpos] = newitem;
53         arr[pos] = parent;
54         pos = parentpos;
55     }
56     return 0;
57 }
58 
59 static int
siftup(PyListObject * heap,Py_ssize_t pos)60 siftup(PyListObject *heap, Py_ssize_t pos)
61 {
62     Py_ssize_t startpos, endpos, childpos, limit;
63     PyObject *tmp1, *tmp2, **arr;
64     int cmp;
65 
66     assert(PyList_Check(heap));
67     endpos = PyList_GET_SIZE(heap);
68     startpos = pos;
69     if (pos >= endpos) {
70         PyErr_SetString(PyExc_IndexError, "index out of range");
71         return -1;
72     }
73 
74     /* Bubble up the smaller child until hitting a leaf. */
75     arr = _PyList_ITEMS(heap);
76     limit = endpos >> 1;         /* smallest pos that has no child */
77     while (pos < limit) {
78         /* Set childpos to index of smaller child.   */
79         childpos = 2*pos + 1;    /* leftmost child position  */
80         if (childpos + 1 < endpos) {
81             cmp = PyObject_RichCompareBool(
82                 arr[childpos],
83                 arr[childpos + 1],
84                 Py_LT);
85             if (cmp < 0)
86                 return -1;
87             childpos += ((unsigned)cmp ^ 1);   /* increment when cmp==0 */
88             arr = _PyList_ITEMS(heap);         /* arr may have changed */
89             if (endpos != PyList_GET_SIZE(heap)) {
90                 PyErr_SetString(PyExc_RuntimeError,
91                                 "list changed size during iteration");
92                 return -1;
93             }
94         }
95         /* Move the smaller child up. */
96         tmp1 = arr[childpos];
97         tmp2 = arr[pos];
98         arr[childpos] = tmp2;
99         arr[pos] = tmp1;
100         pos = childpos;
101     }
102     /* Bubble it up to its final resting place (by sifting its parents down). */
103     return siftdown(heap, startpos, pos);
104 }
105 
106 /*[clinic input]
107 _heapq.heappush
108 
109     heap: object
110     item: object
111     /
112 
113 Push item onto heap, maintaining the heap invariant.
114 [clinic start generated code]*/
115 
116 static PyObject *
_heapq_heappush_impl(PyObject * module,PyObject * heap,PyObject * item)117 _heapq_heappush_impl(PyObject *module, PyObject *heap, PyObject *item)
118 /*[clinic end generated code: output=912c094f47663935 input=7913545cb5118842]*/
119 {
120     if (!PyList_Check(heap)) {
121         PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
122         return NULL;
123     }
124 
125     if (PyList_Append(heap, item))
126         return NULL;
127 
128     if (siftdown((PyListObject *)heap, 0, PyList_GET_SIZE(heap)-1))
129         return NULL;
130     Py_RETURN_NONE;
131 }
132 
133 static PyObject *
heappop_internal(PyObject * heap,int siftup_func (PyListObject *,Py_ssize_t))134 heappop_internal(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
135 {
136     PyObject *lastelt, *returnitem;
137     Py_ssize_t n;
138 
139     if (!PyList_Check(heap)) {
140         PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
141         return NULL;
142     }
143 
144     /* raises IndexError if the heap is empty */
145     n = PyList_GET_SIZE(heap);
146     if (n == 0) {
147         PyErr_SetString(PyExc_IndexError, "index out of range");
148         return NULL;
149     }
150 
151     lastelt = PyList_GET_ITEM(heap, n-1) ;
152     Py_INCREF(lastelt);
153     if (PyList_SetSlice(heap, n-1, n, NULL)) {
154         Py_DECREF(lastelt);
155         return NULL;
156     }
157     n--;
158 
159     if (!n)
160         return lastelt;
161     returnitem = PyList_GET_ITEM(heap, 0);
162     PyList_SET_ITEM(heap, 0, lastelt);
163     if (siftup_func((PyListObject *)heap, 0)) {
164         Py_DECREF(returnitem);
165         return NULL;
166     }
167     return returnitem;
168 }
169 
170 /*[clinic input]
171 _heapq.heappop
172 
173     heap: object
174     /
175 
176 Pop the smallest item off the heap, maintaining the heap invariant.
177 [clinic start generated code]*/
178 
179 static PyObject *
_heapq_heappop(PyObject * module,PyObject * heap)180 _heapq_heappop(PyObject *module, PyObject *heap)
181 /*[clinic end generated code: output=e1bbbc9866bce179 input=9bd36317b806033d]*/
182 {
183     return heappop_internal(heap, siftup);
184 }
185 
186 static PyObject *
heapreplace_internal(PyObject * heap,PyObject * item,int siftup_func (PyListObject *,Py_ssize_t))187 heapreplace_internal(PyObject *heap, PyObject *item, int siftup_func(PyListObject *, Py_ssize_t))
188 {
189     PyObject *returnitem;
190 
191     if (!PyList_Check(heap)) {
192         PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
193         return NULL;
194     }
195 
196     if (PyList_GET_SIZE(heap) == 0) {
197         PyErr_SetString(PyExc_IndexError, "index out of range");
198         return NULL;
199     }
200 
201     returnitem = PyList_GET_ITEM(heap, 0);
202     Py_INCREF(item);
203     PyList_SET_ITEM(heap, 0, item);
204     if (siftup_func((PyListObject *)heap, 0)) {
205         Py_DECREF(returnitem);
206         return NULL;
207     }
208     return returnitem;
209 }
210 
211 
212 /*[clinic input]
213 _heapq.heapreplace
214 
215     heap: object
216     item: object
217     /
218 
219 Pop and return the current smallest value, and add the new item.
220 
221 This is more efficient than heappop() followed by heappush(), and can be
222 more appropriate when using a fixed-size heap.  Note that the value
223 returned may be larger than item!  That constrains reasonable uses of
224 this 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 
230 static PyObject *
_heapq_heapreplace_impl(PyObject * module,PyObject * heap,PyObject * item)231 _heapq_heapreplace_impl(PyObject *module, PyObject *heap, PyObject *item)
232 /*[clinic end generated code: output=82ea55be8fbe24b4 input=e57ae8f4ecfc88e3]*/
233 {
234     return heapreplace_internal(heap, item, siftup);
235 }
236 
237 /*[clinic input]
238 _heapq.heappushpop
239 
240     heap: object
241     item: object
242     /
243 
244 Push item on the heap, then pop and return the smallest item from the heap.
245 
246 The combined action runs more efficiently than heappush() followed by
247 a separate call to heappop().
248 [clinic start generated code]*/
249 
250 static PyObject *
_heapq_heappushpop_impl(PyObject * module,PyObject * heap,PyObject * item)251 _heapq_heappushpop_impl(PyObject *module, PyObject *heap, PyObject *item)
252 /*[clinic end generated code: output=67231dc98ed5774f input=eb48c90ba77b2214]*/
253 {
254     PyObject *returnitem;
255     int cmp;
256 
257     if (!PyList_Check(heap)) {
258         PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
259         return NULL;
260     }
261 
262     if (PyList_GET_SIZE(heap) == 0) {
263         Py_INCREF(item);
264         return item;
265     }
266 
267     cmp = PyObject_RichCompareBool(PyList_GET_ITEM(heap, 0), item, Py_LT);
268     if (cmp < 0)
269         return NULL;
270     if (cmp == 0) {
271         Py_INCREF(item);
272         return item;
273     }
274 
275     if (PyList_GET_SIZE(heap) == 0) {
276         PyErr_SetString(PyExc_IndexError, "index out of range");
277         return NULL;
278     }
279 
280     returnitem = PyList_GET_ITEM(heap, 0);
281     Py_INCREF(item);
282     PyList_SET_ITEM(heap, 0, item);
283     if (siftup((PyListObject *)heap, 0)) {
284         Py_DECREF(returnitem);
285         return NULL;
286     }
287     return returnitem;
288 }
289 
290 static Py_ssize_t
keep_top_bit(Py_ssize_t n)291 keep_top_bit(Py_ssize_t n)
292 {
293     int i = 0;
294 
295     while (n > 1) {
296         n >>= 1;
297         i++;
298     }
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 
322 static PyObject *
cache_friendly_heapify(PyObject * heap,int siftup_func (PyListObject *,Py_ssize_t))323 cache_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 
355 static PyObject *
heapify_internal(PyObject * heap,int siftup_func (PyListObject *,Py_ssize_t))356 heapify_internal(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
357 {
358     Py_ssize_t i, n;
359 
360     if (!PyList_Check(heap)) {
361         PyErr_SetString(PyExc_TypeError, "heap argument must be a list");
362         return NULL;
363     }
364 
365     /* 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     */
369     n = PyList_GET_SIZE(heap);
370     if (n > 2500)
371         return cache_friendly_heapify(heap, siftup_func);
372 
373     /* 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     */
380     for (i = (n >> 1) - 1 ; i >= 0 ; i--)
381         if (siftup_func((PyListObject *)heap, i))
382             return NULL;
383     Py_RETURN_NONE;
384 }
385 
386 /*[clinic input]
387 _heapq.heapify
388 
389     heap: object
390     /
391 
392 Transform list into a heap, in-place, in O(len(heap)) time.
393 [clinic start generated code]*/
394 
395 static PyObject *
_heapq_heapify(PyObject * module,PyObject * heap)396 _heapq_heapify(PyObject *module, PyObject *heap)
397 /*[clinic end generated code: output=11483f23627c4616 input=872c87504b8de970]*/
398 {
399     return heapify_internal(heap, siftup);
400 }
401 
402 static int
siftdown_max(PyListObject * heap,Py_ssize_t startpos,Py_ssize_t pos)403 siftdown_max(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
404 {
405     PyObject *newitem, *parent, **arr;
406     Py_ssize_t parentpos, size;
407     int cmp;
408 
409     assert(PyList_Check(heap));
410     size = PyList_GET_SIZE(heap);
411     if (pos >= size) {
412         PyErr_SetString(PyExc_IndexError, "index out of range");
413         return -1;
414     }
415 
416     /* Follow the path to the root, moving parents down until finding
417        a place newitem fits. */
418     arr = _PyList_ITEMS(heap);
419     newitem = arr[pos];
420     while (pos > startpos) {
421         parentpos = (pos - 1) >> 1;
422         parent = arr[parentpos];
423         cmp = PyObject_RichCompareBool(parent, newitem, Py_LT);
424         if (cmp < 0)
425             return -1;
426         if (size != PyList_GET_SIZE(heap)) {
427             PyErr_SetString(PyExc_RuntimeError,
428                             "list changed size during iteration");
429             return -1;
430         }
431         if (cmp == 0)
432             break;
433         arr = _PyList_ITEMS(heap);
434         parent = arr[parentpos];
435         newitem = arr[pos];
436         arr[parentpos] = newitem;
437         arr[pos] = parent;
438         pos = parentpos;
439     }
440     return 0;
441 }
442 
443 static int
siftup_max(PyListObject * heap,Py_ssize_t pos)444 siftup_max(PyListObject *heap, Py_ssize_t pos)
445 {
446     Py_ssize_t startpos, endpos, childpos, limit;
447     PyObject *tmp1, *tmp2, **arr;
448     int cmp;
449 
450     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     }
457 
458     /* Bubble up the smaller child until hitting a leaf. */
459     arr = _PyList_ITEMS(heap);
460     limit = endpos >> 1;         /* smallest pos that has no child */
461     while (pos < limit) {
462         /* Set childpos to index of smaller child.   */
463         childpos = 2*pos + 1;    /* leftmost child position  */
464         if (childpos + 1 < endpos) {
465             cmp = PyObject_RichCompareBool(
466                 arr[childpos + 1],
467                 arr[childpos],
468                 Py_LT);
469             if (cmp < 0)
470                 return -1;
471             childpos += ((unsigned)cmp ^ 1);   /* increment when cmp==0 */
472             arr = _PyList_ITEMS(heap);         /* arr may have changed */
473             if (endpos != PyList_GET_SIZE(heap)) {
474                 PyErr_SetString(PyExc_RuntimeError,
475                                 "list changed size during iteration");
476                 return -1;
477             }
478         }
479         /* Move the smaller child up. */
480         tmp1 = arr[childpos];
481         tmp2 = arr[pos];
482         arr[childpos] = tmp2;
483         arr[pos] = tmp1;
484         pos = childpos;
485     }
486     /* Bubble it up to its final resting place (by sifting its parents down). */
487     return siftdown_max(heap, startpos, pos);
488 }
489 
490 
491 /*[clinic input]
492 _heapq._heappop_max
493 
494     heap: object
495     /
496 
497 Maxheap variant of heappop.
498 [clinic start generated code]*/
499 
500 static PyObject *
_heapq__heappop_max(PyObject * module,PyObject * heap)501 _heapq__heappop_max(PyObject *module, PyObject *heap)
502 /*[clinic end generated code: output=acd30acf6384b13c input=62ede3ba9117f541]*/
503 {
504     return heappop_internal(heap, siftup_max);
505 }
506 
507 /*[clinic input]
508 _heapq._heapreplace_max
509 
510     heap: object
511     item: object
512     /
513 
514 Maxheap variant of heapreplace.
515 [clinic start generated code]*/
516 
517 static PyObject *
_heapq__heapreplace_max_impl(PyObject * module,PyObject * heap,PyObject * item)518 _heapq__heapreplace_max_impl(PyObject *module, PyObject *heap,
519                              PyObject *item)
520 /*[clinic end generated code: output=8ad7545e4a5e8adb input=6d8f25131e0f0e5f]*/
521 {
522     return heapreplace_internal(heap, item, siftup_max);
523 }
524 
525 /*[clinic input]
526 _heapq._heapify_max
527 
528     heap: object
529     /
530 
531 Maxheap variant of heapify.
532 [clinic start generated code]*/
533 
534 static PyObject *
_heapq__heapify_max(PyObject * module,PyObject * heap)535 _heapq__heapify_max(PyObject *module, PyObject *heap)
536 /*[clinic end generated code: output=1c6bb6b60d6a2133 input=cdfcc6835b14110d]*/
537 {
538     return heapify_internal(heap, siftup_max);
539 }
540 
541 
542 static PyMethodDef heapq_methods[] = {
543     _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 */
552 };
553 
554 PyDoc_STRVAR(module_doc,
555 "Heap queue algorithm (a.k.a. priority queue).\n\
556 \n\
557 Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for\n\
558 all k, counting elements from 0.  For the sake of comparison,\n\
559 non-existing elements are considered to be infinite.  The interesting\n\
560 property of a heap is that a[0] is always its smallest element.\n\
561 \n\
562 Usage:\n\
563 \n\
564 heap = []            # creates an empty heap\n\
565 heappush(heap, item) # pushes a new item on the heap\n\
566 item = heappop(heap) # pops the smallest item from the heap\n\
567 item = heap[0]       # smallest item on the heap without popping it\n\
568 heapify(x)           # transforms list into a heap, in-place, in linear time\n\
569 item = heapreplace(heap, item) # pops and returns smallest item, and adds\n\
570                                # new item; the heap size is unchanged\n\
571 \n\
572 Our 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\
580 These two make it possible to view the heap as a regular Python list\n\
581 without surprises: heap[0] is the smallest item, and heap.sort()\n\
582 maintains the heap invariant!\n");
583 
584 
585 PyDoc_STRVAR(__about__,
586 "Heap queues\n\
587 \n\
588 [explanation by Fran\xc3\xa7ois Pinard]\n\
589 \n\
590 Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for\n\
591 all k, counting elements from 0.  For the sake of comparison,\n\
592 non-existing elements are considered to be infinite.  The interesting\n\
593 property of a heap is that a[0] is always its smallest element.\n"
594 "\n\
595 The strange invariant above is meant to be an efficient memory\n\
596 representation 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\
609 In the tree above, each cell `k' is topping `2*k+1' and `2*k+2'.  In\n\
610 a usual binary tournament we see in sports, each cell is the winner\n\
611 over the two cells it tops, and we can trace the winner down the tree\n\
612 to see all opponents s/he had.  However, in many computer applications\n\
613 of such tournaments, we do not need to trace the history of a winner.\n\
614 To be more memory efficient, when a winner is promoted, we try to\n\
615 replace it by something else at a lower level, and the rule becomes\n\
616 that a cell and the two cells it tops contain three different items,\n\
617 but the top cell \"wins\" over the two topped cells.\n"
618 "\n\
619 If this heap invariant is protected at all time, index 0 is clearly\n\
620 the overall winner.  The simplest algorithmic way to remove it and\n\
621 find the \"next\" winner is to move some loser (let's say cell 30 in the\n\
622 diagram above) into the 0 position, and then percolate this new 0 down\n\
623 the tree, exchanging values, until the invariant is re-established.\n\
624 This is clearly logarithmic on the total number of items in the tree.\n\
625 By iterating over all items, you get an O(n ln n) sort.\n"
626 "\n\
627 A nice feature of this sort is that you can efficiently insert new\n\
628 items while the sort is going on, provided that the inserted items are\n\
629 not \"better\" than the last 0'th element you extracted.  This is\n\
630 especially useful in simulation contexts, where the tree holds all\n\
631 incoming events, and the \"win\" condition means the smallest scheduled\n\
632 time.  When an event schedule other events for execution, they are\n\
633 scheduled into the future, so they can easily go into the heap.  So, a\n\
634 heap is a good structure for implementing schedulers (this is what I\n\
635 used for my MIDI sequencer :-).\n"
636 "\n\
637 Various structures for implementing schedulers have been extensively\n\
638 studied, and heaps are good for this, as they are reasonably speedy,\n\
639 the speed is almost constant, and the worst case is not much different\n\
640 than the average case.  However, there are other representations which\n\
641 are more efficient overall, yet the worst cases might be terrible.\n"
642 "\n\
643 Heaps are also very useful in big disk sorts.  You most probably all\n\
644 know that a big sort implies producing \"runs\" (which are pre-sorted\n\
645 sequences, which size is usually related to the amount of CPU memory),\n\
646 followed by a merging passes for these runs, which merging is often\n\
647 very cleverly organised[1].  It is very important that the initial\n\
648 sort produces the longest runs possible.  Tournaments are a good way\n\
649 to that.  If, using all the memory available to hold a tournament, you\n\
650 replace and percolate items that happen to fit the current run, you'll\n\
651 produce runs which are twice the size of the memory for random input,\n\
652 and much better for input fuzzily ordered.\n"
653 "\n\
654 Moreover, if you output the 0'th item on disk and get an input which\n\
655 may not fit in the current tournament (because the value \"wins\" over\n\
656 the last output value), it cannot fit in the heap, so the size of the\n\
657 heap decreases.  The freed memory could be cleverly reused immediately\n\
658 for progressively building a second heap, which grows at exactly the\n\
659 same rate the first heap is melting.  When the first heap completely\n\
660 vanishes, you switch heaps and start a new run.  Clever and quite\n\
661 effective!\n\
662 \n\
663 In a word, heaps are useful memory structures to know.  I use them in\n\
664 a few applications, and I think it is good to keep a `heap' module\n\
665 around. :-)\n"
666 "\n\
667 --------------------\n\
668 [1] The disk balancing algorithms which are current, nowadays, are\n\
669 more annoying than clever, and this is a consequence of the seeking\n\
670 capabilities of the disks.  On devices which cannot seek, like big\n\
671 tape drives, the story was quite different, and one had to be very\n\
672 clever to ensure (far in advance) that each tape movement will be the\n\
673 most effective possible (that is, will best participate at\n\
674 \"progressing\" the merge).  Some tapes were even able to read\n\
675 backwards, and this was also used to avoid the rewinding time.\n\
676 Believe me, real good tape sorts were quite spectacular to watch!\n\
677 From all times, sorting has always been a Great Art! :-)\n");
678 
679 
680 static struct PyModuleDef _heapqmodule = {
681     PyModuleDef_HEAD_INIT,
682     "_heapq",
683     module_doc,
684     -1,
685     heapq_methods,
686     NULL,
687     NULL,
688     NULL,
689     NULL
690 };
691 
692 PyMODINIT_FUNC
PyInit__heapq(void)693 PyInit__heapq(void)
694 {
695     PyObject *m, *about;
696 
697     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;
703 }
704 
705