d_heap 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,54 +1,29 @@
1
1
  #include <float.h>
2
2
  #include "d_heap.h"
3
3
 
4
- #define SCORE_AS_LONG_DOUBLE 1
5
-
6
4
  ID id_cmp; // <=>
7
5
  ID id_abs; // abs
8
6
 
9
- #ifdef SCORE_AS_LONG_DOUBLE
10
- #define SCORE long double
11
- #else
12
- #define SCORE VALUE
13
- #endif
14
-
15
7
  typedef struct dheap_struct {
16
8
  int d;
17
- VALUE values;
18
- #ifdef SCORE_AS_LONG_DOUBLE
19
9
  long size;
20
10
  long capa;
21
- SCORE *cscores;
22
- #else
23
- VALUE scores; // T_ARRAY of comparable objects
24
- #endif
11
+ ENTRY *entries;
25
12
  } dheap_t;
26
13
 
27
- #define DHEAP_VALUE(heap, idx) RARRAY_AREF((heap)->values, idx)
14
+ #define DHEAP_SCORE(heap, idx) ((heap)->entries[idx].score)
15
+ #define DHEAP_VALUE(heap, idx) ((heap)->entries[idx].value)
28
16
  #define DHEAP_IDX_LAST(heap) (DHEAP_SIZE((heap)) - 1)
29
17
  #define DHEAP_IDX_PARENT(heap, idx) (((idx) - 1) / (heap)->d)
30
- #define DHEAP_IDX_CHILD0(heap, idx) (((idx) * (heap)->d) + 1)
18
+ #define DHEAP_IDX_CHILD_0(heap, idx) (((idx) * (heap)->d) + 1)
19
+ #define DHEAP_IDX_CHILD_D(heap, idx) (((idx) * (heap)->d) + (heap)->d)
31
20
 
32
- #ifdef SCORE_AS_LONG_DOUBLE
33
- #define DHEAP_SIZE(heap) ((heap)->size)
34
- #else
35
- #define DHEAP_SIZE(heap) (RARRAY_LEN((heap)->scores))
36
- #endif
21
+ #define DHEAP_SIZE(heap) ((heap)->size)
37
22
 
38
- #ifdef SCORE_AS_LONG_DOUBLE
39
- #define DHEAP_SCORE(heap, idx) \
40
- (idx < 0 || heap->size <= idx ? (SCORE)0 : \
41
- ((heap)->cscores[idx]))
42
- #else
43
- #define DHEAP_SCORE(heap, idx) RARRAY_AREF((heap)->scores, idx)
44
- #endif
45
-
46
- #ifdef SCORE_AS_LONG_DOUBLE
47
-
48
- #define CMP_LT(a, b) (a < b)
49
- #define CMP_LTE(a, b) (a <= b)
50
- #define CMP_GT(a, b) (a > b)
51
- #define CMP_GTE(a, b) (a >= b)
23
+ #define CMP_LT(a, b) ((a) < (b))
24
+ #define CMP_LTE(a, b) ((a) <= (b))
25
+ #define CMP_GT(a, b) ((a) > (b))
26
+ #define CMP_GTE(a, b) ((a) >= (b))
52
27
 
53
28
  #if LDBL_MANT_DIG < SIZEOF_UNSIGNED_LONG_LONG * 8
54
29
  #error 'unsigned long long' should fit into 'long double' mantissa
@@ -118,7 +93,7 @@ VAL2SCORE(VALUE score)
118
93
  }
119
94
  }
120
95
 
121
- #else
96
+ #ifdef ORIG_SCORE_CMP_CODE
122
97
 
123
98
  #define VAL2SCORE(score) (score)
124
99
 
@@ -169,47 +144,49 @@ optimized_cmp(SCORE a, SCORE b) {
169
144
  } \
170
145
  } while (0)
171
146
 
172
- #define DHEAP_Check_Index(index, last_index) do { \
147
+ #ifdef __D_HEAP_DEBUG
148
+ #define ASSERT_DHEAP_INDEX(heap, index) do { \
173
149
  if (index < 0) { \
174
150
  rb_raise(rb_eIndexError, "DHeap index %ld too small", index); \
175
151
  } \
176
- else if (last_index < index) { \
152
+ else if (DHEAP_IDX_LAST(heap) < index) { \
177
153
  rb_raise(rb_eIndexError, "DHeap index %ld too large", index); \
178
154
  } \
179
155
  } while (0)
156
+ #else
157
+ #define ASSERT_DHEAP_INDEX(heap, index)
158
+ #endif
180
159
 
181
160
  static void
182
161
  dheap_compact(void *ptr)
183
162
  {
184
163
  dheap_t *heap = ptr;
185
- #ifndef SCORE_AS_LONG_DOUBLE
186
- if (heap->scores) dheap_gc_location( heap->scores );
187
- #endif
188
- if (heap->values) dheap_gc_location( heap->values );
164
+ for (long i = 0; i < heap->size; ++i) {
165
+ if (DHEAP_VALUE(heap, i))
166
+ dheap_gc_location(DHEAP_VALUE(heap, i));
167
+ }
189
168
  }
190
169
 
191
170
  static void
192
171
  dheap_mark(void *ptr)
193
172
  {
194
173
  dheap_t *heap = ptr;
195
- #ifndef SCORE_AS_LONG_DOUBLE
196
- if (heap->scores) rb_gc_mark_movable(heap->scores);
197
- #endif
198
- if (heap->values) rb_gc_mark_movable(heap->values);
174
+ for (long i = 0; i < heap->size; ++i) {
175
+ if (DHEAP_VALUE(heap, i))
176
+ rb_gc_mark_movable(DHEAP_VALUE(heap,i));
177
+ }
199
178
  }
200
179
 
201
180
  static void
202
181
  dheap_free(void *ptr)
203
182
  {
204
- #ifdef SCORE_AS_LONG_DOUBLE
205
183
  dheap_t *heap = ptr;
206
184
  heap->size = 0;
207
- if (heap->cscores) {
208
- ruby_xfree(heap->cscores);
209
- heap->cscores = NULL;
185
+ if (heap->entries) {
186
+ xfree(heap->entries);
187
+ heap->entries = NULL;
210
188
  }
211
189
  heap->capa = 0;
212
- #endif
213
190
  xfree(ptr);
214
191
  }
215
192
 
@@ -219,9 +196,7 @@ dheap_memsize(const void *ptr)
219
196
  const dheap_t *heap = ptr;
220
197
  size_t size = 0;
221
198
  size += sizeof(*heap);
222
- #ifdef SCORE_AS_LONG_DOUBLE
223
- size += sizeof(long double) * heap->capa;
224
- #endif
199
+ size += sizeof(ENTRY) * heap->capa;
225
200
  return size;
226
201
  }
227
202
 
@@ -245,15 +220,10 @@ dheap_s_alloc(VALUE klass)
245
220
 
246
221
  obj = TypedData_Make_Struct(klass, dheap_t, &dheap_data_type, heap);
247
222
  heap->d = DHEAP_DEFAULT_D;
248
- heap->values = Qnil;
249
223
 
250
- #ifdef SCORE_AS_LONG_DOUBLE
251
224
  heap->size = 0;
252
225
  heap->capa = 0;
253
- heap->cscores = NULL;
254
- #else
255
- heap->scores = Qnil;
256
- #endif
226
+ heap->entries = NULL;
257
227
 
258
228
  return obj;
259
229
  }
@@ -263,32 +233,21 @@ get_dheap_struct(VALUE self)
263
233
  {
264
234
  dheap_t *heap;
265
235
  TypedData_Get_Struct(self, dheap_t, &dheap_data_type, heap);
266
- Check_Type(heap->values, T_ARRAY); // ensure it's been initialized
267
236
  return heap;
268
237
  }
269
238
 
270
- #ifdef SCORE_AS_LONG_DOUBLE
271
-
272
- static void
239
+ void
273
240
  dheap_set_capa(dheap_t *heap, long new_capa)
274
241
  {
275
- long double *new, *old;
276
242
  // Do nothing if we already have the capacity or are resizing too small
277
- if (new_capa <= heap->capa) return;
278
- if (new_capa <= heap->size) return;
243
+ if (new_capa <= heap->capa || new_capa <= heap->size) return;
279
244
 
280
245
  // allocate
281
- new = ruby_xcalloc(new_capa, sizeof(long double));
282
- old = heap->cscores;
283
-
284
- // copy contents
285
- if (old) {
286
- MEMCPY(new, old, long double, heap->size);
287
- ruby_xfree(old);
246
+ if (heap->entries) {
247
+ RB_REALLOC_N(heap->entries, ENTRY, new_capa);
248
+ } else {
249
+ heap->entries = RB_ZALLOC_N(ENTRY, new_capa);
288
250
  }
289
-
290
- // set vars
291
- heap->cscores = new;
292
251
  heap->capa = new_capa;
293
252
  }
294
253
 
@@ -317,8 +276,6 @@ dheap_ensure_room_for_push(dheap_t *heap, long incr_by)
317
276
  }
318
277
  }
319
278
 
320
- #endif
321
-
322
279
  /*
323
280
  * @overload initialize(d = DHeap::DEFAULT_D)
324
281
  * Initialize a _d_-ary min-heap.
@@ -337,18 +294,12 @@ dheap_initialize(int argc, VALUE *argv, VALUE self) {
337
294
  DHEAP_Check_d_size(d);
338
295
  heap->d = d;
339
296
 
340
- heap->values = rb_ary_new_capa(DHEAP_DEFAULT_SIZE);
341
-
342
- #ifdef SCORE_AS_LONG_DOUBLE
343
297
  dheap_set_capa(heap, DHEAP_DEFAULT_SIZE);
344
- #else
345
- heap->scores = rb_ary_new_capa(DHEAP_DEFAULT_SIZE);
346
- #endif
347
298
 
348
299
  return self;
349
300
  }
350
301
 
351
- /* :nodoc: */
302
+ /* @!visibility private */
352
303
  static VALUE
353
304
  dheap_initialize_copy(VALUE copy, VALUE orig)
354
305
  {
@@ -360,114 +311,82 @@ dheap_initialize_copy(VALUE copy, VALUE orig)
360
311
 
361
312
  heap_copy->d = heap_orig->d;
362
313
 
363
- heap_copy->values = rb_ary_new();
364
- rb_ary_replace(heap_copy->values, heap_orig->values);
365
-
366
- #ifdef SCORE_AS_LONG_DOUBLE
367
314
  dheap_set_capa(heap_copy, heap_orig->capa);
368
315
  heap_copy->size = heap_orig->size;
369
316
  if (heap_copy->size)
370
- MEMCPY(heap_orig->cscores, heap_copy->cscores, long double, heap_orig->size);
371
- #else
372
- heap_copy->scores = rb_ary_new();
373
- rb_ary_replace(heap_copy->scores, heap_orig->scores);
374
- #endif
317
+ MEMCPY(heap_copy->entries, heap_orig->entries, ENTRY, heap_orig->size);
375
318
 
376
319
  return copy;
377
320
  }
378
321
 
379
- static inline void
380
- dheap_assign(dheap_t *heap, long idx, SCORE score, VALUE value)
381
- {
382
- #ifdef SCORE_AS_LONG_DOUBLE
383
- heap->cscores[idx] = score;
384
- rb_ary_store(heap->values, idx, value);
385
- #else
386
- rb_ary_store(heap->scores, idx, score);
387
- rb_ary_store(heap->values, idx, value);
388
- #endif
389
- }
390
-
391
322
  VALUE
392
- dheap_ary_sift_up(dheap_t *heap, long sift_index) {
393
- VALUE sift_value;
394
- SCORE sift_score;
323
+ dheap_sift_up(dheap_t *heap, long index) {
324
+ ENTRY entry = heap->entries[index];
395
325
 
396
- long last_index = DHEAP_IDX_LAST(heap);
397
- DHEAP_Check_Index(sift_index, last_index);
398
-
399
- sift_value = DHEAP_VALUE(heap, sift_index);
400
- sift_score = DHEAP_SCORE(heap, sift_index);
326
+ ASSERT_DHEAP_INDEX(heap, index);
401
327
 
402
328
  // sift it up to where it belongs
403
- for (long parent_index; 0 < sift_index; sift_index = parent_index) {
404
- SCORE parent_score;
405
- VALUE parent_value;
406
-
407
- debug(rb_sprintf("sift up(%"PRIsVALUE", %d, %ld)", heap->values, heap->d, sift_index));
408
- parent_index = DHEAP_IDX_PARENT(heap, sift_index);
409
- parent_score = DHEAP_SCORE(heap, parent_index);
329
+ for (long parent_index; 0 < index; index = parent_index) {
330
+ /* debug(rb_sprintf("sift up(%"PRIsVALUE", %d, %ld)", heap->values, heap->d, index)); */
331
+ parent_index = DHEAP_IDX_PARENT(heap, index);
410
332
 
411
333
  // parent is smaller: heap is restored
412
- if (CMP_LTE(parent_score, sift_score)) break;
334
+ if (CMP_LTE(DHEAP_SCORE(heap, parent_index), entry.score)) break;
413
335
 
414
336
  // parent is larger: swap and continue sifting up
415
- parent_value = DHEAP_VALUE(heap, parent_index);
416
- dheap_assign(heap, sift_index, parent_score, parent_value);
417
- dheap_assign(heap, parent_index, sift_score, sift_value);
337
+ heap->entries[index] = heap->entries[parent_index];
418
338
  }
419
- debug(rb_sprintf("sifted (%"PRIsVALUE", %d, %ld)", heap->values, heap->d, sift_index));
420
- return LONG2NUM(sift_index);
339
+ heap->entries[index] = entry;
340
+ /* debug(rb_sprintf("sifted (%"PRIsVALUE", %d, %ld)", heap->values, heap->d, index)); */
341
+ return LONG2NUM(index);
421
342
  }
422
343
 
423
- VALUE
424
- dheap_ary_sift_down(dheap_t *heap, long sift_index) {
425
- VALUE sift_value;
426
- SCORE sift_score;
427
- long last_index = DHEAP_IDX_LAST(heap);
428
- DHEAP_Check_Index(sift_index, last_index);
429
-
430
- sift_value = DHEAP_VALUE(heap, sift_index);
431
- sift_score = DHEAP_SCORE(heap, sift_index);
432
-
433
- // iteratively sift it down to where it belongs
434
- for (long child_index; sift_index < last_index; sift_index = child_index) {
435
- long child_idx0, last_sibidx;
436
- SCORE child_score;
437
- VALUE child_value;
438
-
439
- // find first child index, and break if we've reached the last layer
440
- child_idx0 = child_index = DHEAP_IDX_CHILD0(heap, sift_index);
441
- debug(rb_sprintf("sift dn(%"PRIsVALUE", %d, %ld)", heap->values, heap->d, sift_index));
442
- if (last_index < child_idx0) break;
443
-
444
- // find the min child (and its child_index)
445
- // requires "d" comparisons to find min child and compare to sift_score
446
- last_sibidx = child_idx0 + heap->d - 1;
447
- if (last_index < last_sibidx) last_sibidx = last_index;
448
- child_score = DHEAP_SCORE(heap, child_idx0);
449
- child_index = child_idx0;
450
- for (long sibling_index = child_idx0 + 1;
451
- sibling_index <= last_sibidx;
452
- ++sibling_index) {
453
- SCORE sibling_score = DHEAP_SCORE(heap, sibling_index);
454
-
455
- if (CMP_LT(sibling_score, child_score)) {
456
- child_score = sibling_score;
457
- child_index = sibling_index;
458
- }
344
+ /*
345
+ * this is a tiny bit more complicated than the binary heap version
346
+ */
347
+ static inline long
348
+ dheap_find_min_child(dheap_t *heap, long parent, long last_index) {
349
+ long min_child = DHEAP_IDX_CHILD_0(heap, parent);
350
+ long last_sib = DHEAP_IDX_CHILD_D(heap, parent);
351
+ if (last_index < last_sib) last_sib = last_index;
352
+
353
+ for (long sibidx = min_child + 1; sibidx <= last_sib; ++sibidx) {
354
+ if (CMP_LT(DHEAP_SCORE(heap, sibidx),
355
+ DHEAP_SCORE(heap, min_child))) {
356
+ min_child = sibidx;
459
357
  }
358
+ }
359
+ return min_child;
360
+ }
361
+
362
+ void
363
+ dheap_sift_down(dheap_t *heap, long index, long last_index) {
364
+ if (last_index < 1 || DHEAP_IDX_PARENT(heap, last_index) < index) {
365
+ // short-circuit: no chance for a child
366
+ return;
367
+
368
+ } else {
369
+ ENTRY entry = heap->entries[index];
370
+
371
+ long last_parent = DHEAP_IDX_PARENT(heap, last_index);
372
+
373
+ ASSERT_DHEAP_INDEX(heap, index);
374
+
375
+ // iteratively sift it down to where it belongs
376
+ while (index <= last_parent) {
377
+ // find min child
378
+ long min_child = dheap_find_min_child(heap, index, last_index);
460
379
 
461
- // child is larger: heap is restored
462
- if (CMP_LTE(sift_score, child_score)) break;
380
+ // child is larger: heap is restored
381
+ if (CMP_LTE(entry.score, DHEAP_SCORE(heap, min_child))) break;
463
382
 
464
- // child is smaller: swap and continue sifting down
465
- child_value = DHEAP_VALUE(heap, child_index);
466
- dheap_assign(heap, sift_index, child_score, child_value);
467
- dheap_assign(heap, child_index, sift_score, sift_value);
383
+ // child is smaller: swap and continue sifting down
384
+ heap->entries[index] = heap->entries[min_child];
385
+ index = min_child;
386
+ }
387
+ heap->entries[index] = entry;
388
+ // debug(rb_sprintf("sifted (%"PRIsVALUE", %d, %ld)", heap->values, heap->d, index));
468
389
  }
469
- debug(rb_sprintf("sifted (%"PRIsVALUE", %d, %ld)", heap->values, heap->d, sift_index));
470
- return LONG2NUM(sift_index);
471
390
  }
472
391
 
473
392
  /*
@@ -482,7 +401,7 @@ dheap_size(VALUE self)
482
401
  }
483
402
 
484
403
  /*
485
- * @return [Boolean] is the heap empty?
404
+ * @return [Boolean] if the heap is empty
486
405
  */
487
406
  static VALUE
488
407
  dheap_empty_p(VALUE self)
@@ -502,24 +421,7 @@ dheap_attr_d(VALUE self)
502
421
  return INT2FIX(heap->d);
503
422
  }
504
423
 
505
- /*
506
- * Freezes the heap as well as its underlying array, but does <i>not</i>
507
- * deep-freeze the elements in the heap.
508
- *
509
- * @return [self]
510
- */
511
- static VALUE
512
- dheap_freeze(VALUE self) {
513
- dheap_t *heap = get_dheap_struct(self);
514
- ID id_freeze = rb_intern("freeze");
515
- rb_funcall(heap->values, id_freeze, 0);
516
- #ifndef SCORE_AS_LONG_DOUBLE
517
- rb_funcall(heap->scores, id_freeze, 0);
518
- #endif
519
- return rb_call_super(0, NULL);
520
- }
521
-
522
- /* :nodoc: */
424
+ /* @!visibility private */
523
425
  static VALUE
524
426
  dheap_init_clone(VALUE clone, VALUE orig, VALUE kwfreeze)
525
427
  {
@@ -530,117 +432,119 @@ dheap_init_clone(VALUE clone, VALUE orig, VALUE kwfreeze)
530
432
  return clone;
531
433
  }
532
434
 
435
+ static inline void
436
+ dheap_push_entry(dheap_t *heap, ENTRY *entry) {
437
+ dheap_ensure_room_for_push(heap, 1);
438
+ heap->entries[heap->size] = *entry;
439
+ ++heap->size;
440
+ dheap_sift_up(heap, heap->size - 1);
441
+ }
442
+
533
443
  /*
534
- * @overload push(score, value = score)
444
+ * Inserts a value into the heap, using a score to determine sort-order.
445
+ *
446
+ * Score comes first, as an analogy with the +Array#insert+ index.
447
+ *
448
+ * Time complexity: <b>O(log n / log d)</b> <i>(worst-case)</i>
449
+ *
450
+ * @param score [Integer,Float,#to_f] a score to compare against other scores.
451
+ * @param value [Object] an object that is associated with the score.
452
+ *
453
+ * @return [self]
454
+ */
455
+ static VALUE
456
+ dheap_insert(VALUE self, VALUE score, VALUE value) {
457
+ ENTRY entry;
458
+ dheap_t *heap = get_dheap_struct(self);
459
+ rb_check_frozen(self);
460
+
461
+ entry.score = VAL2SCORE(score);
462
+ entry.value = value;
463
+ dheap_push_entry(heap, &entry);
464
+
465
+ return self;
466
+ }
467
+
468
+ /*
469
+ * @overload push(value, score = value)
535
470
  *
536
471
  * Push a value onto heap, using a score to determine sort-order.
537
472
  *
538
- * Ideally, the score should be a frozen value that can be efficiently compared
539
- * to other scores, e.g. an Integer or Float or (maybe) a String
473
+ * Value comes first because the separate score is optional, and because it feels
474
+ * like a more natural variation on +Array#push+ or +Queue#enq+. If a score
475
+ * isn't provided, the value must be an Integer or can be cast with
476
+ * +Float(value)+.
540
477
  *
541
478
  * Time complexity: <b>O(log n / log d)</b> <i>(worst-case)</i>
542
479
  *
543
- * @param score [#<=>] a value that can be compared to other scores.
544
480
  * @param value [Object] an object that is associated with the score.
481
+ * @param score [Integer,Float,#to_f] a score to compare against other scores.
545
482
  *
546
- * @return [Integer] the index of the value's final position.
483
+ * @return [self]
547
484
  */
548
485
  static VALUE
549
486
  dheap_push(int argc, VALUE *argv, VALUE self) {
550
- VALUE scr, val;
551
- dheap_t *heap;
552
- long last_index;
487
+ dheap_t *heap = get_dheap_struct(self);
488
+ ENTRY entry;
553
489
  rb_check_frozen(self);
554
490
 
555
491
  rb_check_arity(argc, 1, 2);
556
- heap = get_dheap_struct(self);
557
- scr = argv[0];
558
- val = argc < 2 ? scr : argv[1];
559
-
560
- #ifdef SCORE_AS_LONG_DOUBLE
561
- do {
562
- long double score_as_ldbl = VAL2SCORE(scr);
563
- dheap_ensure_room_for_push(heap, 1);
564
- ++heap->size;
565
- last_index = DHEAP_IDX_LAST(heap);
566
- heap->cscores[last_index] = score_as_ldbl;
567
- } while (0);
568
- #else
569
- rb_ary_push((heap)->scores, scr);
570
- last_index = DHEAP_IDX_LAST(heap);
571
- #endif
572
- rb_ary_push((heap)->values, val);
492
+ entry.value = argv[0];
493
+ entry.score = VAL2SCORE(argc < 2 ? entry.value : argv[1]);
494
+ dheap_push_entry(heap, &entry);
573
495
 
574
- return dheap_ary_sift_up(heap, last_index);
496
+ return self;
575
497
  }
576
498
 
577
499
  /*
578
- * Pushes a comparable value onto the heap.
500
+ * Pushes a value onto the heap.
579
501
  *
580
- * The value will be its own score.
502
+ * The score will be derived from the value, by using the value itself if it is
503
+ * an Integer, otherwise by casting it with +Float(value)+.
581
504
  *
582
505
  * Time complexity: <b>O(log n / log d)</b> <i>(worst-case)</i>
583
506
  *
584
- * @param value [#<=>] a value that can be compared to other heap members.
507
+ * @param value [Integer,#to_f] a value with an intrinsic numeric score
585
508
  * @return [self]
586
509
  */
587
510
  static VALUE
588
511
  dheap_left_shift(VALUE self, VALUE value) {
589
- dheap_push(1, &value, self);
512
+ dheap_t *heap = get_dheap_struct(self);
513
+ ENTRY entry;
514
+ rb_check_frozen(self);
515
+
516
+ entry.score = VAL2SCORE(value);
517
+ entry.value = value;
518
+ dheap_push_entry(heap, &entry);
519
+
590
520
  return self;
591
521
  }
592
522
 
593
- #ifdef SCORE_AS_LONG_DOUBLE
594
- #define DHEAP_DROP_LAST(heap) do { \
595
- rb_ary_pop(heap->values); \
596
- --heap->size; \
597
- } while (0)
598
- #else
599
- #define DHEAP_DROP_LAST(heap) do { \
600
- rb_ary_pop(heap->values); \
601
- rb_ary_pop(heap->scores); \
602
- } while (0)
603
- #endif
604
- static inline void
605
- dheap_pop_swap_last_and_sift_down(dheap_t *heap, long last_index)
523
+ static const ENTRY EmptyDheapEntry;
524
+
525
+ static inline VALUE
526
+ dheap_pop0(dheap_t *heap)
606
527
  {
607
- if (last_index == 0) {
608
- DHEAP_DROP_LAST(heap);
609
- }
610
- else
611
- {
612
- VALUE sift_value = DHEAP_VALUE(heap, last_index);
613
- SCORE sift_score = DHEAP_SCORE(heap, last_index);
614
- dheap_assign(heap, 0, sift_score, sift_value);
615
- DHEAP_DROP_LAST(heap);
616
- dheap_ary_sift_down(heap, 0);
528
+ VALUE popped = DHEAP_VALUE(heap, 0);
529
+ if (0 < --heap->size) {
530
+ heap->entries[0] = heap->entries[heap->size];
531
+ heap->entries[heap->size] = EmptyDheapEntry; // unnecessary to zero?
532
+ dheap_sift_down(heap, 0, heap->size - 1);
617
533
  }
534
+ return popped;
618
535
  }
619
536
 
620
- #ifdef SCORE_AS_LONG_DOUBLE
621
- #define DHEAP_CLEAR(heap) do { \
622
- rb_ary_clear(heap->values); \
623
- heap->size = 0; \
624
- } while (0)
625
- #else
626
- #define DHEAP_CLEAR(heap) do { \
627
- rb_ary_clear(heap->values); \
628
- rb_ary_clear(heap->scores); \
629
- } while (0)
630
- #endif
631
-
632
537
  /*
633
- * Returns the next value on the heap to be popped without popping it.
538
+ * Clears all values from the heap, leaving it empty.
634
539
  *
635
- * Time complexity: <b>O(1)</b> <i>(worst-case)</i>
636
- * @return [Object] the next value to be popped without popping it.
540
+ * @return [self]
637
541
  */
638
542
  static VALUE
639
543
  dheap_clear(VALUE self) {
640
544
  dheap_t *heap = get_dheap_struct(self);
641
545
  rb_check_frozen(self);
642
546
  if (0 < DHEAP_SIZE(heap)) {
643
- DHEAP_CLEAR(heap);
547
+ heap->size = 0;
644
548
  }
645
549
  return self;
646
550
  }
@@ -652,7 +556,8 @@ dheap_clear(VALUE self) {
652
556
  * @return [Object] the next value to be popped without popping it.
653
557
  */
654
558
  static VALUE
655
- dheap_peek(VALUE self) {
559
+ dheap_peek(VALUE self)
560
+ {
656
561
  dheap_t *heap = get_dheap_struct(self);
657
562
  if (DHEAP_IDX_LAST(heap) < 0) return Qnil;
658
563
  return DHEAP_VALUE(heap, 0);
@@ -662,73 +567,66 @@ dheap_peek(VALUE self) {
662
567
  * Pops the minimum value from the top of the heap
663
568
  *
664
569
  * Time complexity: <b>O(d log n / log d)</b> <i>(worst-case)</i>
570
+ *
571
+ * @return [Object] the value with the minimum score
572
+ *
573
+ * @see #peek
574
+ * @see #pop_lt
575
+ * @see #pop_lte
665
576
  */
666
577
  static VALUE
667
- dheap_pop(VALUE self) {
668
- VALUE pop_value;
578
+ dheap_pop(VALUE self)
579
+ {
669
580
  dheap_t *heap = get_dheap_struct(self);
670
- long last_index = DHEAP_IDX_LAST(heap);
671
581
  rb_check_frozen(self);
672
-
673
- if (last_index < 0) return Qnil;
674
- pop_value = DHEAP_VALUE(heap, 0);
675
-
676
- dheap_pop_swap_last_and_sift_down(heap, last_index);
677
- return pop_value;
582
+ if (DHEAP_SIZE(heap) <= 0) return Qnil;
583
+ return dheap_pop0(heap);
678
584
  }
679
585
 
680
586
  /*
681
587
  * Pops the minimum value only if it is less than or equal to a max score.
682
588
  *
683
- * @param max_score [#to_f] the maximum score to be popped
589
+ * @param max_score [Integer,#to_f] the maximum score to be popped
590
+ *
591
+ * Time complexity: <b>O(d log n / log d)</b> <i>(worst-case)</i>
592
+ *
593
+ * @return [Object] the value with the minimum score
684
594
  *
595
+ * @see #peek
685
596
  * @see #pop
597
+ * @see #pop_lt
686
598
  */
687
599
  static VALUE
688
- dheap_pop_lte(VALUE self, VALUE max_score) {
689
- VALUE pop_value;
600
+ dheap_pop_lte(VALUE self, VALUE max_score)
601
+ {
690
602
  dheap_t *heap = get_dheap_struct(self);
691
- long last_index = DHEAP_IDX_LAST(heap);
692
603
  rb_check_frozen(self);
693
-
694
- if (last_index < 0) return Qnil;
695
- pop_value = DHEAP_VALUE(heap, 0);
696
-
697
- do {
698
- SCORE max = VAL2SCORE(max_score);
699
- SCORE pop_score = DHEAP_SCORE(heap, 0);
700
- if (max && !CMP_LTE(pop_score, max)) return Qnil;
701
- } while (0);
702
-
703
- dheap_pop_swap_last_and_sift_down(heap, last_index);
704
- return pop_value;
604
+ if (DHEAP_SIZE(heap) <= 0) return Qnil;
605
+ if (!CMP_LTE(DHEAP_SCORE(heap, 0), VAL2SCORE(max_score))) return Qnil;
606
+ return dheap_pop0(heap);
705
607
  }
706
608
 
707
609
  /*
708
610
  * Pops the minimum value only if it is less than a max score.
709
611
  *
710
- * @param max_score [#to_f] the maximum score to be popped
612
+ * @param max_score [Integer,#to_f] the maximum score to be popped
711
613
  *
712
614
  * Time complexity: <b>O(d log n / log d)</b> <i>(worst-case)</i>
615
+ *
616
+ * @return [Object] the value with the minimum score
617
+ *
618
+ * @see #peek
619
+ * @see #pop
620
+ * @see #pop_lte
713
621
  */
714
622
  static VALUE
715
- dheap_pop_lt(VALUE self, VALUE max_score) {
716
- VALUE pop_value;
623
+ dheap_pop_lt(VALUE self, VALUE max_score)
624
+ {
717
625
  dheap_t *heap = get_dheap_struct(self);
718
- long last_index = DHEAP_IDX_LAST(heap);
719
626
  rb_check_frozen(self);
720
-
721
- if (last_index < 0) return Qnil;
722
- pop_value = DHEAP_VALUE(heap, 0);
723
-
724
- do {
725
- SCORE max = VAL2SCORE(max_score);
726
- SCORE pop_score = DHEAP_SCORE(heap, 0);
727
- if (max && !CMP_LT(pop_score, max)) return Qnil;
728
- } while (0);
729
-
730
- dheap_pop_swap_last_and_sift_down(heap, last_index);
731
- return pop_value;
627
+ if (DHEAP_SIZE(heap) <= 0) return Qnil;
628
+ if (!CMP_LT(DHEAP_SCORE(heap, 0), VAL2SCORE(max_score))) return Qnil;
629
+ return dheap_pop0(heap);
732
630
  }
733
631
 
734
632
  void
@@ -740,13 +638,12 @@ Init_d_heap(void)
740
638
  rb_cDHeap = rb_define_class("DHeap", rb_cObject);
741
639
  rb_define_alloc_func(rb_cDHeap, dheap_s_alloc);
742
640
 
743
- rb_define_const(rb_cDHeap, "MAX_D", INT2NUM(DHEAP_MAX_D));
641
+ rb_define_const(rb_cDHeap, "MAX_D", INT2NUM(DHEAP_MAX_D));
744
642
  rb_define_const(rb_cDHeap, "DEFAULT_D", INT2NUM(DHEAP_DEFAULT_D));
745
643
 
746
644
  rb_define_method(rb_cDHeap, "initialize", dheap_initialize, -1);
747
645
  rb_define_method(rb_cDHeap, "initialize_copy", dheap_initialize_copy, 1);
748
646
  rb_define_private_method(rb_cDHeap, "__init_clone__", dheap_init_clone, 2);
749
- rb_define_method(rb_cDHeap, "freeze", dheap_freeze, 0);
750
647
 
751
648
  rb_define_method(rb_cDHeap, "d", dheap_attr_d, 0);
752
649
  rb_define_method(rb_cDHeap, "size", dheap_size, 0);
@@ -754,6 +651,7 @@ Init_d_heap(void)
754
651
  rb_define_method(rb_cDHeap, "peek", dheap_peek, 0);
755
652
 
756
653
  rb_define_method(rb_cDHeap, "clear", dheap_clear, 0);
654
+ rb_define_method(rb_cDHeap, "insert", dheap_insert, 2);
757
655
  rb_define_method(rb_cDHeap, "push", dheap_push, -1);
758
656
  rb_define_method(rb_cDHeap, "<<", dheap_left_shift, 1);
759
657
  rb_define_method(rb_cDHeap, "pop", dheap_pop, 0);