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