d_heap 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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);