d_heap 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,392 @@
1
+ Profiling run at 2021-01-10 21:34:56 -0500
2
+ ruby v2.7.2, DHeap v0.3.0
3
+
4
+ ~~~~~~ filling @dheap_bm_random_vals with 1.0M ~~~~~~
5
+ ########################################################################
6
+ # Profile w/ N=5 (i=1000000)
7
+ # (n.b. RubyProf & tracepoint can change relative performance.
8
+ # A sampling profiler can provide more accurate relative metrics.
9
+ ########################################################################
10
+
11
+ Filling push and resort ---------------------------
12
+ Profiling push and resort ---------------------------
13
+ Measure Mode: wall_time
14
+ Thread ID: 1360
15
+ Fiber ID: 1340
16
+ Total: 2.639873
17
+ Sort by: self_time
18
+
19
+ %self total self wait child calls name location
20
+ 31.49 2.640 0.831 0.000 1.808 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
21
+ 25.69 1.219 0.678 0.000 0.541 1000000 DHeap::Benchmarks::Sorting#<< /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:35
22
+ 15.00 0.396 0.396 0.000 0.000 1000000 Array#sort!
23
+ 12.38 0.462 0.327 0.000 0.136 1000000 DHeap::Benchmarks::Sorting#pop /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:42
24
+ 5.50 0.145 0.145 0.000 0.000 1000000 Array#push
25
+ 5.13 0.136 0.136 0.000 0.000 1000000 Array#shift
26
+ 4.81 0.127 0.127 0.000 0.000 1000000 Array#fetch
27
+
28
+ * recursively called methods
29
+
30
+ Columns are:
31
+
32
+ %self - The percentage of time spent in this method, derived from self_time/total_time.
33
+ total - The time spent in this method and its children.
34
+ self - The time spent in this method.
35
+ wait - The amount of time this method waited for other threads.
36
+ child - The time spent in this method's children.
37
+ calls - The number of times this method was called.
38
+ name - The name of the method.
39
+ location - The location of the method.
40
+
41
+ The interpretation of method names is:
42
+
43
+ * MyObject#test - An instance method "test" of the class "MyObject"
44
+ * <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
45
+
46
+ Filling bsearch + insert ---------------------------
47
+ Profiling bsearch + insert ---------------------------
48
+ Measure Mode: wall_time
49
+ Thread ID: 1360
50
+ Fiber ID: 1340
51
+ Total: 2.634233
52
+ Sort by: self_time
53
+
54
+ %self total self wait child calls name location
55
+ 30.73 2.634 0.810 0.000 1.825 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
56
+ 25.94 1.228 0.683 0.000 0.545 1000000 DHeap::Benchmarks::BSearch#<< /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:61
57
+ 14.83 0.391 0.391 0.000 0.000 1000000 Array#bsearch_index
58
+ 12.79 0.462 0.337 0.000 0.125 1000000 DHeap::Benchmarks::BSearch#pop /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:70
59
+ 5.85 0.154 0.154 0.000 0.000 1000000 Array#insert
60
+ 5.10 0.134 0.134 0.000 0.000 1000000 Array#fetch
61
+ 4.76 0.125 0.125 0.000 0.000 1000000 Array#pop
62
+
63
+ * recursively called methods
64
+
65
+ Columns are:
66
+
67
+ %self - The percentage of time spent in this method, derived from self_time/total_time.
68
+ total - The time spent in this method and its children.
69
+ self - The time spent in this method.
70
+ wait - The amount of time this method waited for other threads.
71
+ child - The time spent in this method's children.
72
+ calls - The number of times this method was called.
73
+ name - The name of the method.
74
+ location - The location of the method.
75
+
76
+ The interpretation of method names is:
77
+
78
+ * MyObject#test - An instance method "test" of the class "MyObject"
79
+ * <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
80
+
81
+ Filling ruby binary heap ---------------------------
82
+ Profiling ruby binary heap ---------------------------
83
+ Measure Mode: wall_time
84
+ Thread ID: 1360
85
+ Fiber ID: 1340
86
+ Total: 4.940103
87
+ Sort by: self_time
88
+
89
+ %self total self wait child calls name location
90
+ 37.38 1.973 1.846 0.000 0.126 1000000 DHeap::Benchmarks::RbHeap#<< /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:80
91
+ 33.66 2.042 1.663 0.000 0.380 1000000 DHeap::Benchmarks::RbHeap#pop /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:96
92
+ 16.10 4.940 0.795 0.000 4.145 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
93
+ 2.64 0.130 0.130 0.000 0.000 1000000 Array#pop
94
+ 2.63 0.130 0.130 0.000 0.000 1000000 Array#first
95
+ 2.62 0.130 0.130 0.000 0.000 1000000 Array#fetch
96
+ 2.56 0.126 0.126 0.000 0.000 1000000 Array#push
97
+ 2.43 0.120 0.120 0.000 0.000 1000000 Array#last
98
+
99
+ * recursively called methods
100
+
101
+ Columns are:
102
+
103
+ %self - The percentage of time spent in this method, derived from self_time/total_time.
104
+ total - The time spent in this method and its children.
105
+ self - The time spent in this method.
106
+ wait - The amount of time this method waited for other threads.
107
+ child - The time spent in this method's children.
108
+ calls - The number of times this method was called.
109
+ name - The name of the method.
110
+ location - The location of the method.
111
+
112
+ The interpretation of method names is:
113
+
114
+ * MyObject#test - An instance method "test" of the class "MyObject"
115
+ * <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
116
+
117
+ Filling quaternary DHeap ---------------------------
118
+ Profiling quaternary DHeap ---------------------------
119
+ Measure Mode: wall_time
120
+ Thread ID: 1360
121
+ Fiber ID: 1340
122
+ Total: 1.231464
123
+ Sort by: self_time
124
+
125
+ %self total self wait child calls name location
126
+ 60.13 1.231 0.741 0.000 0.491 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
127
+ 16.72 0.206 0.206 0.000 0.000 1000000 DHeap#<<
128
+ 12.85 0.158 0.158 0.000 0.000 1000000 DHeap#pop
129
+ 10.30 0.127 0.127 0.000 0.000 1000000 Array#fetch
130
+
131
+ * recursively called methods
132
+
133
+ Columns are:
134
+
135
+ %self - The percentage of time spent in this method, derived from self_time/total_time.
136
+ total - The time spent in this method and its children.
137
+ self - The time spent in this method.
138
+ wait - The amount of time this method waited for other threads.
139
+ child - The time spent in this method's children.
140
+ calls - The number of times this method was called.
141
+ name - The name of the method.
142
+ location - The location of the method.
143
+
144
+ The interpretation of method names is:
145
+
146
+ * MyObject#test - An instance method "test" of the class "MyObject"
147
+ * <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
148
+
149
+ ########################################################################
150
+ # Profile w/ N=1365 (i=1000000)
151
+ # (n.b. RubyProf & tracepoint can change relative performance.
152
+ # A sampling profiler can provide more accurate relative metrics.
153
+ ########################################################################
154
+
155
+ Filling push and resort ---------------------------
156
+ Profiling push and resort ---------------------------
157
+ Measure Mode: wall_time
158
+ Thread ID: 1360
159
+ Fiber ID: 1340
160
+ Total: 41.950612
161
+ Sort by: self_time
162
+
163
+ %self total self wait child calls name location
164
+ 94.10 39.478 39.478 0.000 0.000 1000000 Array#sort!
165
+ 2.11 41.951 0.884 0.000 41.066 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
166
+ 1.68 40.328 0.707 0.000 39.621 1000000 DHeap::Benchmarks::Sorting#<< /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:35
167
+
168
+ * recursively called methods
169
+
170
+ Columns are:
171
+
172
+ %self - The percentage of time spent in this method, derived from self_time/total_time.
173
+ total - The time spent in this method and its children.
174
+ self - The time spent in this method.
175
+ wait - The amount of time this method waited for other threads.
176
+ child - The time spent in this method's children.
177
+ calls - The number of times this method was called.
178
+ name - The name of the method.
179
+ location - The location of the method.
180
+
181
+ The interpretation of method names is:
182
+
183
+ * MyObject#test - An instance method "test" of the class "MyObject"
184
+ * <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
185
+
186
+ Filling bsearch + insert ---------------------------
187
+ Profiling bsearch + insert ---------------------------
188
+ Measure Mode: wall_time
189
+ Thread ID: 1360
190
+ Fiber ID: 1340
191
+ Total: 3.559064
192
+ Sort by: self_time
193
+
194
+ %self total self wait child calls name location
195
+ 37.92 1.349 1.349 0.000 0.000 1000000 Array#bsearch_index
196
+ 22.76 3.559 0.810 0.000 2.749 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
197
+ 18.47 2.157 0.657 0.000 1.499 1000000 DHeap::Benchmarks::BSearch#<< /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:61
198
+ 9.45 0.462 0.336 0.000 0.125 1000000 DHeap::Benchmarks::BSearch#pop /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:70
199
+ 4.21 0.150 0.150 0.000 0.000 1000000 Array#insert
200
+ 3.67 0.131 0.131 0.000 0.000 1000000 Array#fetch
201
+ 3.53 0.125 0.125 0.000 0.000 1000000 Array#pop
202
+
203
+ * recursively called methods
204
+
205
+ Columns are:
206
+
207
+ %self - The percentage of time spent in this method, derived from self_time/total_time.
208
+ total - The time spent in this method and its children.
209
+ self - The time spent in this method.
210
+ wait - The amount of time this method waited for other threads.
211
+ child - The time spent in this method's children.
212
+ calls - The number of times this method was called.
213
+ name - The name of the method.
214
+ location - The location of the method.
215
+
216
+ The interpretation of method names is:
217
+
218
+ * MyObject#test - An instance method "test" of the class "MyObject"
219
+ * <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
220
+
221
+ Filling ruby binary heap ---------------------------
222
+ Profiling ruby binary heap ---------------------------
223
+ Measure Mode: wall_time
224
+ Thread ID: 1360
225
+ Fiber ID: 1340
226
+ Total: 11.581886
227
+ Sort by: self_time
228
+
229
+ %self total self wait child calls name location
230
+ 52.04 6.160 6.027 0.000 0.132 1000000 DHeap::Benchmarks::RbHeap#<< /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:80
231
+ 35.10 4.453 4.065 0.000 0.388 1000000 DHeap::Benchmarks::RbHeap#pop /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:96
232
+ 7.21 11.582 0.835 0.000 10.747 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
233
+ 1.16 0.134 0.134 0.000 0.000 1000000 Array#fetch
234
+ 1.14 0.132 0.132 0.000 0.000 1000000 Array#push
235
+ 1.14 0.132 0.132 0.000 0.000 1000000 Array#pop
236
+ 1.13 0.131 0.131 0.000 0.000 1000000 Array#first
237
+ 1.08 0.125 0.125 0.000 0.000 1000000 Array#last
238
+
239
+ * recursively called methods
240
+
241
+ Columns are:
242
+
243
+ %self - The percentage of time spent in this method, derived from self_time/total_time.
244
+ total - The time spent in this method and its children.
245
+ self - The time spent in this method.
246
+ wait - The amount of time this method waited for other threads.
247
+ child - The time spent in this method's children.
248
+ calls - The number of times this method was called.
249
+ name - The name of the method.
250
+ location - The location of the method.
251
+
252
+ The interpretation of method names is:
253
+
254
+ * MyObject#test - An instance method "test" of the class "MyObject"
255
+ * <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
256
+
257
+ Filling quaternary DHeap ---------------------------
258
+ Profiling quaternary DHeap ---------------------------
259
+ Measure Mode: wall_time
260
+ Thread ID: 1360
261
+ Fiber ID: 1340
262
+ Total: 1.431426
263
+ Sort by: self_time
264
+
265
+ %self total self wait child calls name location
266
+ 50.61 1.431 0.724 0.000 0.707 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
267
+ 21.61 0.309 0.309 0.000 0.000 1000000 DHeap#<<
268
+ 19.18 0.275 0.275 0.000 0.000 1000000 DHeap#pop
269
+ 8.59 0.123 0.123 0.000 0.000 1000000 Array#fetch
270
+
271
+ * recursively called methods
272
+
273
+ Columns are:
274
+
275
+ %self - The percentage of time spent in this method, derived from self_time/total_time.
276
+ total - The time spent in this method and its children.
277
+ self - The time spent in this method.
278
+ wait - The amount of time this method waited for other threads.
279
+ child - The time spent in this method's children.
280
+ calls - The number of times this method was called.
281
+ name - The name of the method.
282
+ location - The location of the method.
283
+
284
+ The interpretation of method names is:
285
+
286
+ * MyObject#test - An instance method "test" of the class "MyObject"
287
+ * <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
288
+
289
+ ########################################################################
290
+ # Profile w/ N=87381 (i=1000000)
291
+ # (n.b. RubyProf & tracepoint can change relative performance.
292
+ # A sampling profiler can provide more accurate relative metrics.
293
+ ########################################################################
294
+
295
+ Filling bsearch + insert ---------------------------
296
+ Profiling bsearch + insert ---------------------------
297
+ Measure Mode: wall_time
298
+ Thread ID: 1360
299
+ Fiber ID: 1340
300
+ Total: 5.894803
301
+ Sort by: self_time
302
+
303
+ %self total self wait child calls name location
304
+ 34.53 2.035 2.035 0.000 0.000 1000000 Array#bsearch_index
305
+ 30.22 1.782 1.782 0.000 0.000 1000000 Array#insert
306
+ 13.74 5.895 0.810 0.000 5.085 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
307
+ 11.52 4.496 0.679 0.000 3.817 1000000 DHeap::Benchmarks::BSearch#<< /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:61
308
+ 5.70 0.459 0.336 0.000 0.124 1000000 DHeap::Benchmarks::BSearch#pop /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:70
309
+ 2.20 0.130 0.130 0.000 0.000 1000000 Array#fetch
310
+ 2.10 0.124 0.124 0.000 0.000 1000000 Array#pop
311
+
312
+ * recursively called methods
313
+
314
+ Columns are:
315
+
316
+ %self - The percentage of time spent in this method, derived from self_time/total_time.
317
+ total - The time spent in this method and its children.
318
+ self - The time spent in this method.
319
+ wait - The amount of time this method waited for other threads.
320
+ child - The time spent in this method's children.
321
+ calls - The number of times this method was called.
322
+ name - The name of the method.
323
+ location - The location of the method.
324
+
325
+ The interpretation of method names is:
326
+
327
+ * MyObject#test - An instance method "test" of the class "MyObject"
328
+ * <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
329
+
330
+ Filling ruby binary heap ---------------------------
331
+ Profiling ruby binary heap ---------------------------
332
+ Measure Mode: wall_time
333
+ Thread ID: 1360
334
+ Fiber ID: 1340
335
+ Total: 16.514635
336
+ Sort by: self_time
337
+
338
+ %self total self wait child calls name location
339
+ 45.67 7.926 7.542 0.000 0.384 1000000 DHeap::Benchmarks::RbHeap#pop /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:96
340
+ 45.43 7.630 7.502 0.000 0.128 1000000 DHeap::Benchmarks::RbHeap#<< /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:80
341
+ 5.00 16.515 0.826 0.000 15.688 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
342
+
343
+ * recursively called methods
344
+
345
+ Columns are:
346
+
347
+ %self - The percentage of time spent in this method, derived from self_time/total_time.
348
+ total - The time spent in this method and its children.
349
+ self - The time spent in this method.
350
+ wait - The amount of time this method waited for other threads.
351
+ child - The time spent in this method's children.
352
+ calls - The number of times this method was called.
353
+ name - The name of the method.
354
+ location - The location of the method.
355
+
356
+ The interpretation of method names is:
357
+
358
+ * MyObject#test - An instance method "test" of the class "MyObject"
359
+ * <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
360
+
361
+ Filling quaternary DHeap ---------------------------
362
+ Profiling quaternary DHeap ---------------------------
363
+ Measure Mode: wall_time
364
+ Thread ID: 1360
365
+ Fiber ID: 1340
366
+ Total: 1.622729
367
+ Sort by: self_time
368
+
369
+ %self total self wait child calls name location
370
+ 44.66 1.623 0.725 0.000 0.898 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
371
+ 27.42 0.445 0.445 0.000 0.000 1000000 DHeap#pop
372
+ 20.41 0.331 0.331 0.000 0.000 1000000 DHeap#<<
373
+ 7.51 0.122 0.122 0.000 0.000 1000000 Array#fetch
374
+
375
+ * recursively called methods
376
+
377
+ Columns are:
378
+
379
+ %self - The percentage of time spent in this method, derived from self_time/total_time.
380
+ total - The time spent in this method and its children.
381
+ self - The time spent in this method.
382
+ wait - The amount of time this method waited for other threads.
383
+ child - The time spent in this method's children.
384
+ calls - The number of times this method was called.
385
+ name - The name of the method.
386
+ location - The location of the method.
387
+
388
+ The interpretation of method names is:
389
+
390
+ * MyObject#test - An instance method "test" of the class "MyObject"
391
+ * <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
392
+
@@ -1,58 +1,190 @@
1
+ #include <float.h>
1
2
  #include "d_heap.h"
2
3
 
4
+ #define SCORE_AS_LONG_DOUBLE 1
5
+
3
6
  ID id_cmp; // <=>
4
- ID id_ivar_values;
5
- ID id_ivar_scores;
6
- ID id_ivar_d;
7
+ ID id_abs; // abs
7
8
 
8
- #define Get_DHeap(hobj, hstruct) ((hstruct) = get_dheap_struct(hobj))
9
+ #ifdef SCORE_AS_LONG_DOUBLE
10
+ #define SCORE long double
11
+ #else
12
+ #define SCORE VALUE
13
+ #endif
9
14
 
10
- #define DHEAP_IDX_LAST(heap) (DHEAP_SIZE(heap) - 1)
11
- #define DHEAP_IDX_PARENT(heap, idx) ((idx - 1) / heap->d)
12
- #define DHEAP_IDX_CHILD0(heap, idx) ((idx * heap->d) + 1)
15
+ typedef struct dheap_struct {
16
+ int d;
17
+ VALUE values;
18
+ #ifdef SCORE_AS_LONG_DOUBLE
19
+ long size;
20
+ long capa;
21
+ SCORE *cscores;
22
+ #else
23
+ VALUE scores; // T_ARRAY of comparable objects
24
+ #endif
25
+ } dheap_t;
13
26
 
14
- #define DHEAP_SIZE(heap) (RARRAY_LEN((heap)->scores))
15
27
  #define DHEAP_VALUE(heap, idx) RARRAY_AREF((heap)->values, idx)
16
- #define DHEAP_SCORE(heap, idx) RARRAY_AREF((heap)->scores, idx)
17
- #define DHEAP_ASSIGN(heap, idx, scr, val) \
18
- rb_ary_store(heap->scores, idx, scr); \
19
- rb_ary_store(heap->values, idx, val);
20
- #define DHEAP_APPEND(heap, scr, val) \
21
- rb_ary_push((heap)->scores, scr); \
22
- rb_ary_push((heap)->values, val);
23
- #define DHEAP_DROP_LAST(heap) ( \
24
- rb_ary_pop(heap->scores), \
25
- rb_ary_pop(heap->values) \
26
- ) // score, value
28
+ #define DHEAP_IDX_LAST(heap) (DHEAP_SIZE((heap)) - 1)
29
+ #define DHEAP_IDX_PARENT(heap, idx) (((idx) - 1) / (heap)->d)
30
+ #define DHEAP_IDX_CHILD0(heap, idx) (((idx) * (heap)->d) + 1)
31
+
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
37
+
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)
52
+
53
+ #if LDBL_MANT_DIG < SIZEOF_UNSIGNED_LONG_LONG * 8
54
+ #error 'unsigned long long' should fit into 'long double' mantissa
55
+ #endif
56
+
57
+ // copied and modified from ruby's object.c
58
+ #define FIX2SCORE(x) (long double)FIX2LONG(x)
59
+ // We could translate a much wider range of values to long double by
60
+ // implementing a new `rb_big2ldbl(x)` function. But requires reaching into
61
+ // T_BIGNUM internals.
62
+ static inline long double
63
+ BIG2SCORE(VALUE x)
64
+ {
65
+ if (RBIGNUM_POSITIVE_P(x)) {
66
+ unsigned long long ull = rb_big2ull(x);
67
+ return (long double)ull;
68
+ } else {
69
+ unsigned long long ull;
70
+ long double ldbl;
71
+ x = rb_funcall(x, id_abs, 0);
72
+ ull = rb_big2ull(x);
73
+ ldbl = (long double) ull;
74
+ return -ldbl;
75
+ }
76
+ }
77
+ #define INT2SCORE(x) \
78
+ (FIXNUM_P(x) ? FIX2SCORE(x) : BIG2SCORE(x))
79
+ #define NUM2SCORE(x) \
80
+ (FIXNUM_P(x) ? FIX2SCORE(x) : \
81
+ RB_TYPE_P(x, T_BIGNUM) ? BIG2SCORE(x) : \
82
+ (Check_Type(x, T_FLOAT), (long double)RFLOAT_VALUE(x)))
83
+ static inline long double
84
+ RAT2SCORE(VALUE x)
85
+ {
86
+ VALUE num = rb_rational_num(x);
87
+ VALUE den = rb_rational_den(x);
88
+ return NUM2SCORE(num) / NUM2SCORE(den);
89
+ }
90
+
91
+ /*
92
+ * Convert both T_FIXNUM and T_FLOAT (and sometimes T_BIGNUM, T_RATIONAL,
93
+ * String, etc) to SCORE
94
+ * * with no loss of precision (where possible for Integer and Float),
95
+ * * raises an exception if
96
+ * * a positive integer is too large for unsigned long long (should be 64bit)
97
+ * * a negative integer is too small for signed long long (should be 64bit)
98
+ * * reduced to long double (should be 80 or 128 bit) if it is Rational
99
+ * * reduced to double precision if the value is convertable by Float(x)
100
+ */
101
+ static inline long double
102
+ VAL2SCORE(VALUE score)
103
+ {
104
+ // assert that long double can hold 'unsigned long long':
105
+ // static_assert(sizeof(unsigned long long) * 8 <= LDBL_MANT_DIG);
106
+ // assert that long double can hold T_FLOAT
107
+ // static_assert(sizeof(double) <= sizeof(long double));
108
+
109
+ switch (TYPE(score)) {
110
+ case T_FIXNUM:
111
+ return FIX2SCORE(score);
112
+ case T_BIGNUM:
113
+ return BIG2SCORE(score);
114
+ case T_RATIONAL:
115
+ return RAT2SCORE(score);
116
+ default:
117
+ return (long double)(NUM2DBL(rb_Float(score)));
118
+ }
119
+ }
120
+
121
+ #else
122
+
123
+ #define VAL2SCORE(score) (score)
124
+
125
+ #define CMP_LT(a, b) (optimized_cmp(a, b) < 0)
126
+ #define CMP_LTE(a, b) (optimized_cmp(a, b) <= 0)
127
+ #define CMP_GT(a, b) (optimized_cmp(a, b) > 0)
128
+ #define CMP_GTE(a, b) (optimized_cmp(a, b) >= 0)
27
129
 
28
- #define DHEAP_Check_d_size(d) \
29
- if (d < 2) { \
130
+ // from internal/compar.h
131
+ #define STRING_P(s) (RB_TYPE_P((s), T_STRING) && CLASS_OF(s) == rb_cString)
132
+ /*
133
+ * short-circuit evaluation for a few basic types.
134
+ *
135
+ * Only Integer, Float, and String are optimized,
136
+ * and only when both arguments are the same type.
137
+ */
138
+ static inline int
139
+ optimized_cmp(SCORE a, SCORE b) {
140
+ if (a == b) // Fixnum equality and object equality
141
+ return 0;
142
+ if (FIXNUM_P(a) && FIXNUM_P(b))
143
+ return (FIX2LONG(a) < FIX2LONG(b)) ? -1 : 1;
144
+ if (RB_FLOAT_TYPE_P(a) && RB_FLOAT_TYPE_P(b))
145
+ {
146
+ double x, y;
147
+ x = RFLOAT_VALUE(a);
148
+ y = RFLOAT_VALUE(b);
149
+ if (isnan(x) || isnan(y)) rb_cmperr(a, b); // raise ArgumentError
150
+ return (x < y) ? -1 : ((x == y) ? 0 : 1);
151
+ }
152
+ if (RB_TYPE_P(a, T_BIGNUM) && RB_TYPE_P(b, T_BIGNUM))
153
+ return FIX2INT(rb_big_cmp(a, b));
154
+ if (STRING_P(a) && STRING_P(b))
155
+ return rb_str_cmp(a, b);
156
+
157
+ // give up on an optimized version and just call (a <=> b)
158
+ return rb_cmpint(rb_funcallv(a, id_cmp, 1, &b), a, b);
159
+ }
160
+
161
+ #endif
162
+
163
+ #define DHEAP_Check_d_size(d) do { \
164
+ if (d < 2) { \
30
165
  rb_raise(rb_eArgError, "DHeap d=%d is too small", d); \
31
- } \
32
- if (d > DHEAP_MAX_D) { \
166
+ } \
167
+ if (d > DHEAP_MAX_D) { \
33
168
  rb_raise(rb_eArgError, "DHeap d=%d is too large", d); \
34
- }
169
+ } \
170
+ } while (0)
35
171
 
36
- #define DHEAP_Check_Index(index, last_index) \
37
- if (index < 0) { \
172
+ #define DHEAP_Check_Index(index, last_index) do { \
173
+ if (index < 0) { \
38
174
  rb_raise(rb_eIndexError, "DHeap index %ld too small", index); \
39
- } \
40
- else if (last_index < index) { \
175
+ } \
176
+ else if (last_index < index) { \
41
177
  rb_raise(rb_eIndexError, "DHeap index %ld too large", index); \
42
- }
43
-
44
- struct dheap_struct {
45
- int d;
46
- VALUE scores;
47
- VALUE values;
48
- };
49
- typedef struct dheap_struct dheap_t;
178
+ } \
179
+ } while (0)
50
180
 
51
181
  static void
52
182
  dheap_compact(void *ptr)
53
183
  {
54
184
  dheap_t *heap = ptr;
185
+ #ifndef SCORE_AS_LONG_DOUBLE
55
186
  if (heap->scores) dheap_gc_location( heap->scores );
187
+ #endif
56
188
  if (heap->values) dheap_gc_location( heap->values );
57
189
  }
58
190
 
@@ -60,15 +192,36 @@ static void
60
192
  dheap_mark(void *ptr)
61
193
  {
62
194
  dheap_t *heap = ptr;
195
+ #ifndef SCORE_AS_LONG_DOUBLE
63
196
  if (heap->scores) rb_gc_mark_movable(heap->scores);
197
+ #endif
64
198
  if (heap->values) rb_gc_mark_movable(heap->values);
65
199
  }
66
200
 
201
+ static void
202
+ dheap_free(void *ptr)
203
+ {
204
+ #ifdef SCORE_AS_LONG_DOUBLE
205
+ dheap_t *heap = ptr;
206
+ heap->size = 0;
207
+ if (heap->cscores) {
208
+ ruby_xfree(heap->cscores);
209
+ heap->cscores = NULL;
210
+ }
211
+ heap->capa = 0;
212
+ #endif
213
+ xfree(ptr);
214
+ }
215
+
67
216
  static size_t
68
217
  dheap_memsize(const void *ptr)
69
218
  {
70
219
  const dheap_t *heap = ptr;
71
- size_t size = sizeof(*heap);
220
+ size_t size = 0;
221
+ size += sizeof(*heap);
222
+ #ifdef SCORE_AS_LONG_DOUBLE
223
+ size += sizeof(long double) * heap->capa;
224
+ #endif
72
225
  return size;
73
226
  }
74
227
 
@@ -76,7 +229,7 @@ static const rb_data_type_t dheap_data_type = {
76
229
  "DHeap",
77
230
  {
78
231
  (void (*)(void*))dheap_mark,
79
- (void (*)(void*))RUBY_DEFAULT_FREE,
232
+ (void (*)(void*))dheap_free,
80
233
  (size_t (*)(const void *))dheap_memsize,
81
234
  dheap_compact_callback(dheap_compact),
82
235
  },
@@ -92,9 +245,16 @@ dheap_s_alloc(VALUE klass)
92
245
 
93
246
  obj = TypedData_Make_Struct(klass, dheap_t, &dheap_data_type, heap);
94
247
  heap->d = DHEAP_DEFAULT_D;
95
- heap->scores = Qnil;
96
248
  heap->values = Qnil;
97
249
 
250
+ #ifdef SCORE_AS_LONG_DOUBLE
251
+ heap->size = 0;
252
+ heap->capa = 0;
253
+ heap->cscores = NULL;
254
+ #else
255
+ heap->scores = Qnil;
256
+ #endif
257
+
98
258
  return obj;
99
259
  }
100
260
 
@@ -103,10 +263,62 @@ get_dheap_struct(VALUE self)
103
263
  {
104
264
  dheap_t *heap;
105
265
  TypedData_Get_Struct(self, dheap_t, &dheap_data_type, heap);
106
- Check_Type(heap->scores, T_ARRAY);
266
+ Check_Type(heap->values, T_ARRAY); // ensure it's been initialized
107
267
  return heap;
108
268
  }
109
269
 
270
+ #ifdef SCORE_AS_LONG_DOUBLE
271
+
272
+ static void
273
+ dheap_set_capa(dheap_t *heap, long new_capa)
274
+ {
275
+ long double *new, *old;
276
+ // 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;
279
+
280
+ // 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);
288
+ }
289
+
290
+ // set vars
291
+ heap->cscores = new;
292
+ heap->capa = new_capa;
293
+ }
294
+
295
+ static void
296
+ dheap_ensure_room_for_push(dheap_t *heap, long incr_by)
297
+ {
298
+ long new_size = heap->size + incr_by;
299
+
300
+ // check for overflow of new_size
301
+ if (DHEAP_MAX_SIZE - incr_by < heap->size)
302
+ rb_raise(rb_eIndexError, "index %ld too big", new_size);
303
+
304
+ // if it existing capacity is too small
305
+ if (heap->capa < new_size) {
306
+ // double it...
307
+ long new_capa = new_size * 2;
308
+ if (DHEAP_CAPA_INCR_MAX < new_size)
309
+ new_size = new_size + DHEAP_CAPA_INCR_MAX;
310
+ // check for overflow of new_capa
311
+ if (DHEAP_MAX_SIZE / 2 < new_size) new_capa = DHEAP_MAX_SIZE;
312
+ // cap max incr_by
313
+ if (heap->capa + DHEAP_CAPA_INCR_MAX < new_capa)
314
+ new_capa = heap->capa + DHEAP_CAPA_INCR_MAX;
315
+
316
+ dheap_set_capa(heap, new_capa);
317
+ }
318
+ }
319
+
320
+ #endif
321
+
110
322
  /*
111
323
  * @overload initialize(d = DHeap::DEFAULT_D)
112
324
  * Initialize a _d_-ary min-heap.
@@ -115,107 +327,94 @@ get_dheap_struct(VALUE self)
115
327
  */
116
328
  static VALUE
117
329
  dheap_initialize(int argc, VALUE *argv, VALUE self) {
118
- rb_check_arity(argc, 0, 1);
119
330
  dheap_t *heap;
331
+ int d;
332
+
333
+ rb_check_arity(argc, 0, 1);
120
334
  TypedData_Get_Struct(self, dheap_t, &dheap_data_type, heap);
121
335
 
122
- int d = DHEAP_DEFAULT_D;
123
- if (argc) {
124
- d = NUM2INT(argv[0]);
125
- }
336
+ d = argc ? NUM2INT(argv[0]) : DHEAP_DEFAULT_D;
126
337
  DHEAP_Check_d_size(d);
127
338
  heap->d = d;
128
339
 
129
- heap->scores = rb_ary_new_capa(10000);
130
- heap->values = rb_ary_new_capa(10000);
340
+ heap->values = rb_ary_new_capa(DHEAP_DEFAULT_SIZE);
341
+
342
+ #ifdef SCORE_AS_LONG_DOUBLE
343
+ dheap_set_capa(heap, DHEAP_DEFAULT_SIZE);
344
+ #else
345
+ heap->scores = rb_ary_new_capa(DHEAP_DEFAULT_SIZE);
346
+ #endif
131
347
 
132
348
  return self;
133
349
  }
134
350
 
135
- /*
136
- static inline VALUE
137
- make_dheap_element(VALUE score, VALUE value)
351
+ /* :nodoc: */
352
+ static VALUE
353
+ dheap_initialize_copy(VALUE copy, VALUE orig)
138
354
  {
139
- elem_t *elem;
140
- VALUE obj = TypedData_Make_Struct(
141
- rb_cObject,
142
- elem_t,
143
- &dheap_elem_type,
144
- elem);
145
- elem->score = score;
146
- elem->value = value;
147
- return obj;
148
- }
355
+ dheap_t *heap_copy;
356
+ dheap_t *heap_orig = get_dheap_struct(orig);
149
357
 
150
- #define IsDHeapElem(value) rb_typeddata_is_kind_of((value), &dheap_elem_type)
151
- #define Get_DHeap_Elem(value) \
152
- TypedData_Get_Struct((obj), elem_t, &dheap_elem_type, (elem))
358
+ rb_check_frozen(copy);
359
+ TypedData_Get_Struct(copy, dheap_t, &dheap_data_type, heap_copy);
153
360
 
154
- static inline elem_t *
155
- get_dheap_element(VALUE obj)
156
- {
157
- elem_t *elem;
158
- TypedData_Get_Struct((obj), elem_t, &dheap_elem_type, (elem));
159
- return elem;
160
- }
361
+ heap_copy->d = heap_orig->d;
161
362
 
162
- */
363
+ heap_copy->values = rb_ary_new();
364
+ rb_ary_replace(heap_copy->values, heap_orig->values);
163
365
 
164
- #define CMP_LT(a, b) (optimized_cmp(a, b) < 0)
165
- #define CMP_LTE(a, b) (optimized_cmp(a, b) <= 0)
166
- #define CMP_GT(a, b) (optimized_cmp(a, b) > 0)
167
- #define CMP_GTE(a, b) (optimized_cmp(a, b) >= 0)
366
+ #ifdef SCORE_AS_LONG_DOUBLE
367
+ dheap_set_capa(heap_copy, heap_orig->capa);
368
+ heap_copy->size = heap_orig->size;
369
+ 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
168
375
 
169
- /*
170
- * short-circuit evaluation for a few basic types.
171
- *
172
- * Only Integer, Float, and String are optimized,
173
- * and only when both arguments are the same type.
174
- */
175
- static inline int
176
- optimized_cmp(VALUE a, VALUE b) {
177
- if (a == b) // Fixnum equality and object equality
178
- return 0;
179
- if (FIXNUM_P(a) && FIXNUM_P(b))
180
- return (FIX2LONG(a) < FIX2LONG(b)) ? -1 : 1;
181
- if (RB_FLOAT_TYPE_P(a) && RB_FLOAT_TYPE_P(b))
182
- {
183
- double x, y;
184
- x = RFLOAT_VALUE(a);
185
- y = RFLOAT_VALUE(b);
186
- if (isnan(x) || isnan(y)) rb_cmperr(a, b); // raise ArgumentError
187
- return (x < y) ? -1 : ((x == y) ? 0 : 1);
188
- }
189
- if (RB_TYPE_P(a, T_BIGNUM) && RB_TYPE_P(b, T_BIGNUM))
190
- return FIX2INT(rb_big_cmp(a, b));
191
- if (STRING_P(a) && STRING_P(b))
192
- return rb_str_cmp(a, b);
376
+ return copy;
377
+ }
193
378
 
194
- // give up on an optimized version and just call (a <=> b)
195
- return rb_cmpint(rb_funcallv(a, id_cmp, 1, &b), a, b);
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
196
389
  }
197
390
 
198
391
  VALUE
199
392
  dheap_ary_sift_up(dheap_t *heap, long sift_index) {
393
+ VALUE sift_value;
394
+ SCORE sift_score;
395
+
200
396
  long last_index = DHEAP_IDX_LAST(heap);
201
397
  DHEAP_Check_Index(sift_index, last_index);
202
398
 
203
- VALUE sift_value = DHEAP_VALUE(heap, sift_index);
204
- VALUE sift_score = DHEAP_SCORE(heap, sift_index);
399
+ sift_value = DHEAP_VALUE(heap, sift_index);
400
+ sift_score = DHEAP_SCORE(heap, sift_index);
205
401
 
206
402
  // sift it up to where it belongs
207
403
  for (long parent_index; 0 < sift_index; sift_index = parent_index) {
404
+ SCORE parent_score;
405
+ VALUE parent_value;
406
+
208
407
  debug(rb_sprintf("sift up(%"PRIsVALUE", %d, %ld)", heap->values, heap->d, sift_index));
209
408
  parent_index = DHEAP_IDX_PARENT(heap, sift_index);
210
- VALUE parent_score = DHEAP_SCORE(heap, parent_index);
409
+ parent_score = DHEAP_SCORE(heap, parent_index);
211
410
 
212
411
  // parent is smaller: heap is restored
213
412
  if (CMP_LTE(parent_score, sift_score)) break;
214
413
 
215
414
  // parent is larger: swap and continue sifting up
216
- VALUE parent_value = DHEAP_VALUE(heap, parent_index);
217
- DHEAP_ASSIGN(heap, sift_index, parent_score, parent_value);
218
- DHEAP_ASSIGN(heap, parent_index, sift_score, sift_value);
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);
219
418
  }
220
419
  debug(rb_sprintf("sifted (%"PRIsVALUE", %d, %ld)", heap->values, heap->d, sift_index));
221
420
  return LONG2NUM(sift_index);
@@ -223,29 +422,35 @@ dheap_ary_sift_up(dheap_t *heap, long sift_index) {
223
422
 
224
423
  VALUE
225
424
  dheap_ary_sift_down(dheap_t *heap, long sift_index) {
425
+ VALUE sift_value;
426
+ SCORE sift_score;
226
427
  long last_index = DHEAP_IDX_LAST(heap);
227
428
  DHEAP_Check_Index(sift_index, last_index);
228
429
 
229
- VALUE sift_value = DHEAP_VALUE(heap, sift_index);
230
- VALUE sift_score = DHEAP_SCORE(heap, sift_index);
430
+ sift_value = DHEAP_VALUE(heap, sift_index);
431
+ sift_score = DHEAP_SCORE(heap, sift_index);
231
432
 
232
433
  // iteratively sift it down to where it belongs
233
434
  for (long child_index; sift_index < last_index; sift_index = child_index) {
234
- debug(rb_sprintf("sift dn(%"PRIsVALUE", %d, %ld)", heap->values, heap->d, sift_index));
435
+ long child_idx0, last_sibidx;
436
+ SCORE child_score;
437
+ VALUE child_value;
438
+
235
439
  // find first child index, and break if we've reached the last layer
236
- long child_idx0 = child_index = DHEAP_IDX_CHILD0(heap, sift_index);
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));
237
442
  if (last_index < child_idx0) break;
238
443
 
239
444
  // find the min child (and its child_index)
240
445
  // requires "d" comparisons to find min child and compare to sift_score
241
- long last_sibidx = child_idx0 + heap->d - 1;
446
+ last_sibidx = child_idx0 + heap->d - 1;
242
447
  if (last_index < last_sibidx) last_sibidx = last_index;
243
- VALUE child_score = DHEAP_SCORE(heap, child_idx0);
448
+ child_score = DHEAP_SCORE(heap, child_idx0);
244
449
  child_index = child_idx0;
245
450
  for (long sibling_index = child_idx0 + 1;
246
451
  sibling_index <= last_sibidx;
247
452
  ++sibling_index) {
248
- VALUE sibling_score = DHEAP_SCORE(heap, sibling_index);
453
+ SCORE sibling_score = DHEAP_SCORE(heap, sibling_index);
249
454
 
250
455
  if (CMP_LT(sibling_score, child_score)) {
251
456
  child_score = sibling_score;
@@ -257,9 +462,9 @@ dheap_ary_sift_down(dheap_t *heap, long sift_index) {
257
462
  if (CMP_LTE(sift_score, child_score)) break;
258
463
 
259
464
  // child is smaller: swap and continue sifting down
260
- VALUE child_value = DHEAP_VALUE(heap, child_index);
261
- DHEAP_ASSIGN(heap, sift_index, child_score, child_value);
262
- DHEAP_ASSIGN(heap, child_index, sift_score, sift_value);
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);
263
468
  }
264
469
  debug(rb_sprintf("sifted (%"PRIsVALUE", %d, %ld)", heap->values, heap->d, sift_index));
265
470
  return LONG2NUM(sift_index);
@@ -307,11 +512,24 @@ static VALUE
307
512
  dheap_freeze(VALUE self) {
308
513
  dheap_t *heap = get_dheap_struct(self);
309
514
  ID id_freeze = rb_intern("freeze");
310
- rb_funcall(heap->scores, id_freeze, 0);
311
515
  rb_funcall(heap->values, id_freeze, 0);
516
+ #ifndef SCORE_AS_LONG_DOUBLE
517
+ rb_funcall(heap->scores, id_freeze, 0);
518
+ #endif
312
519
  return rb_call_super(0, NULL);
313
520
  }
314
521
 
522
+ /* :nodoc: */
523
+ static VALUE
524
+ dheap_init_clone(VALUE clone, VALUE orig, VALUE kwfreeze)
525
+ {
526
+ dheap_initialize_copy(clone, orig);
527
+ if (RTEST(kwfreeze) || (kwfreeze == Qnil && OBJ_FROZEN(orig))) {
528
+ rb_funcall(clone, rb_intern("freeze"), 0);
529
+ }
530
+ return clone;
531
+ }
532
+
315
533
  /*
316
534
  * @overload push(score, value = score)
317
535
  *
@@ -329,14 +547,30 @@ dheap_freeze(VALUE self) {
329
547
  */
330
548
  static VALUE
331
549
  dheap_push(int argc, VALUE *argv, VALUE self) {
332
- rb_check_arity(argc, 1, 2);
333
- VALUE scr = argv[0];
334
- VALUE val = argc < 2 ? scr : argv[1];
550
+ VALUE scr, val;
551
+ dheap_t *heap;
552
+ long last_index;
553
+ rb_check_frozen(self);
335
554
 
336
- dheap_t *heap = get_dheap_struct(self);
555
+ 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);
337
573
 
338
- DHEAP_APPEND(heap, scr, val);
339
- long last_index = DHEAP_IDX_LAST(heap);
340
574
  return dheap_ary_sift_up(heap, last_index);
341
575
  }
342
576
 
@@ -356,14 +590,17 @@ dheap_left_shift(VALUE self, VALUE value) {
356
590
  return self;
357
591
  }
358
592
 
359
- /*
360
- dheap_t hstruct; \
361
- Get_DHeap(self, hstruct); \
362
- VALUE values = hstruct.values; \
363
- VALUE scores = hstruct.scores; \
364
- VALUE dval = INT2FIX(hstruct.d); \
365
- */
366
-
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
367
604
  static inline void
368
605
  dheap_pop_swap_last_and_sift_down(dheap_t *heap, long last_index)
369
606
  {
@@ -373,13 +610,41 @@ dheap_pop_swap_last_and_sift_down(dheap_t *heap, long last_index)
373
610
  else
374
611
  {
375
612
  VALUE sift_value = DHEAP_VALUE(heap, last_index);
376
- VALUE sift_score = DHEAP_SCORE(heap, last_index);
377
- DHEAP_ASSIGN(heap, 0, sift_score, sift_value);
613
+ SCORE sift_score = DHEAP_SCORE(heap, last_index);
614
+ dheap_assign(heap, 0, sift_score, sift_value);
378
615
  DHEAP_DROP_LAST(heap);
379
616
  dheap_ary_sift_down(heap, 0);
380
617
  }
381
618
  }
382
619
 
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
+ /*
633
+ * Returns the next value on the heap to be popped without popping it.
634
+ *
635
+ * Time complexity: <b>O(1)</b> <i>(worst-case)</i>
636
+ * @return [Object] the next value to be popped without popping it.
637
+ */
638
+ static VALUE
639
+ dheap_clear(VALUE self) {
640
+ dheap_t *heap = get_dheap_struct(self);
641
+ rb_check_frozen(self);
642
+ if (0 < DHEAP_SIZE(heap)) {
643
+ DHEAP_CLEAR(heap);
644
+ }
645
+ return self;
646
+ }
647
+
383
648
  /*
384
649
  * Returns the next value on the heap to be popped without popping it.
385
650
  *
@@ -400,11 +665,13 @@ dheap_peek(VALUE self) {
400
665
  */
401
666
  static VALUE
402
667
  dheap_pop(VALUE self) {
668
+ VALUE pop_value;
403
669
  dheap_t *heap = get_dheap_struct(self);
404
670
  long last_index = DHEAP_IDX_LAST(heap);
671
+ rb_check_frozen(self);
405
672
 
406
673
  if (last_index < 0) return Qnil;
407
- VALUE pop_value = DHEAP_VALUE(heap, 0);
674
+ pop_value = DHEAP_VALUE(heap, 0);
408
675
 
409
676
  dheap_pop_swap_last_and_sift_down(heap, last_index);
410
677
  return pop_value;
@@ -413,20 +680,25 @@ dheap_pop(VALUE self) {
413
680
  /*
414
681
  * Pops the minimum value only if it is less than or equal to a max score.
415
682
  *
416
- * @param max_score [#<=>] the maximum score to be popped
683
+ * @param max_score [#to_f] the maximum score to be popped
417
684
  *
418
685
  * @see #pop
419
686
  */
420
687
  static VALUE
421
688
  dheap_pop_lte(VALUE self, VALUE max_score) {
689
+ VALUE pop_value;
422
690
  dheap_t *heap = get_dheap_struct(self);
423
691
  long last_index = DHEAP_IDX_LAST(heap);
692
+ rb_check_frozen(self);
424
693
 
425
694
  if (last_index < 0) return Qnil;
426
- VALUE pop_value = DHEAP_VALUE(heap, 0);
695
+ pop_value = DHEAP_VALUE(heap, 0);
427
696
 
428
- VALUE pop_score = DHEAP_SCORE(heap, 0);
429
- if (max_score && !CMP_LTE(pop_score, max_score)) return Qnil;
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);
430
702
 
431
703
  dheap_pop_swap_last_and_sift_down(heap, last_index);
432
704
  return pop_value;
@@ -435,20 +707,25 @@ dheap_pop_lte(VALUE self, VALUE max_score) {
435
707
  /*
436
708
  * Pops the minimum value only if it is less than a max score.
437
709
  *
438
- * @param max_score [#<=>] the maximum score to be popped
710
+ * @param max_score [#to_f] the maximum score to be popped
439
711
  *
440
712
  * Time complexity: <b>O(d log n / log d)</b> <i>(worst-case)</i>
441
713
  */
442
714
  static VALUE
443
715
  dheap_pop_lt(VALUE self, VALUE max_score) {
716
+ VALUE pop_value;
444
717
  dheap_t *heap = get_dheap_struct(self);
445
718
  long last_index = DHEAP_IDX_LAST(heap);
719
+ rb_check_frozen(self);
446
720
 
447
721
  if (last_index < 0) return Qnil;
448
- VALUE pop_value = DHEAP_VALUE(heap, 0);
722
+ pop_value = DHEAP_VALUE(heap, 0);
449
723
 
450
- VALUE pop_score = DHEAP_SCORE(heap, 0);
451
- if (max_score && !CMP_LT(pop_score, max_score)) return Qnil;
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);
452
729
 
453
730
  dheap_pop_swap_last_and_sift_down(heap, last_index);
454
731
  return pop_value;
@@ -458,9 +735,7 @@ void
458
735
  Init_d_heap(void)
459
736
  {
460
737
  id_cmp = rb_intern_const("<=>");
461
- id_ivar_values = rb_intern_const("values");
462
- id_ivar_scores = rb_intern_const("scores");
463
- id_ivar_d = rb_intern_const("d");
738
+ id_abs = rb_intern_const("abs");
464
739
 
465
740
  rb_cDHeap = rb_define_class("DHeap", rb_cObject);
466
741
  rb_define_alloc_func(rb_cDHeap, dheap_s_alloc);
@@ -469,13 +744,16 @@ Init_d_heap(void)
469
744
  rb_define_const(rb_cDHeap, "DEFAULT_D", INT2NUM(DHEAP_DEFAULT_D));
470
745
 
471
746
  rb_define_method(rb_cDHeap, "initialize", dheap_initialize, -1);
472
- rb_define_method(rb_cDHeap, "d", dheap_attr_d, 0);
747
+ rb_define_method(rb_cDHeap, "initialize_copy", dheap_initialize_copy, 1);
748
+ rb_define_private_method(rb_cDHeap, "__init_clone__", dheap_init_clone, 2);
473
749
  rb_define_method(rb_cDHeap, "freeze", dheap_freeze, 0);
474
750
 
475
- rb_define_method(rb_cDHeap, "size", dheap_size, 0);
476
- rb_define_method(rb_cDHeap, "empty?", dheap_empty_p, 0);
477
-
751
+ rb_define_method(rb_cDHeap, "d", dheap_attr_d, 0);
752
+ rb_define_method(rb_cDHeap, "size", dheap_size, 0);
753
+ rb_define_method(rb_cDHeap, "empty?", dheap_empty_p, 0);
478
754
  rb_define_method(rb_cDHeap, "peek", dheap_peek, 0);
755
+
756
+ rb_define_method(rb_cDHeap, "clear", dheap_clear, 0);
479
757
  rb_define_method(rb_cDHeap, "push", dheap_push, -1);
480
758
  rb_define_method(rb_cDHeap, "<<", dheap_left_shift, 1);
481
759
  rb_define_method(rb_cDHeap, "pop", dheap_pop, 0);