d_heap 0.3.0 → 0.4.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.
@@ -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);