d_heap 0.2.2 → 0.6.1
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.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +2 -2
- data/.gitignore +1 -0
- data/.rubocop.yml +40 -1
- data/.yardopts +10 -0
- data/CHANGELOG.md +76 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +26 -1
- data/N +7 -0
- data/README.md +358 -147
- data/benchmarks/perf.rb +29 -0
- data/benchmarks/push_n.yml +35 -0
- data/benchmarks/push_n_pop_n.yml +52 -0
- data/benchmarks/push_pop.yml +32 -0
- data/benchmarks/stackprof.rb +31 -0
- data/bin/bench_charts +13 -0
- data/bin/bench_n +7 -0
- data/bin/benchmark-driver +29 -0
- data/bin/benchmarks +10 -0
- data/bin/profile +10 -0
- data/d_heap.gemspec +5 -2
- data/docs/benchmarks-2.txt +75 -0
- data/docs/benchmarks-mem.txt +39 -0
- data/docs/benchmarks.txt +515 -0
- data/docs/profile.txt +392 -0
- data/ext/d_heap/d_heap.c +824 -246
- data/ext/d_heap/extconf.rb +16 -3
- data/images/push_n.png +0 -0
- data/images/push_n_pop_n.png +0 -0
- data/images/push_pop.png +0 -0
- data/images/wikipedia-min-heap.png +0 -0
- data/lib/benchmark_driver/runner/ips_zero_fail.rb +158 -0
- data/lib/d_heap.rb +92 -3
- data/lib/d_heap/benchmarks.rb +112 -0
- data/lib/d_heap/benchmarks/benchmarker.rb +116 -0
- data/lib/d_heap/benchmarks/implementations.rb +224 -0
- data/lib/d_heap/benchmarks/profiler.rb +71 -0
- data/lib/d_heap/benchmarks/rspec_matchers.rb +352 -0
- data/lib/d_heap/version.rb +1 -1
- metadata +60 -6
- data/ext/d_heap/d_heap.h +0 -65
data/docs/profile.txt
ADDED
@@ -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
|
+
|
data/ext/d_heap/d_heap.c
CHANGED
@@ -1,377 +1,955 @@
|
|
1
|
-
#include
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
#
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
#
|
24
|
-
#
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
1
|
+
#include <float.h>
|
2
|
+
#include <math.h>
|
3
|
+
#include "ruby.h"
|
4
|
+
|
5
|
+
/********************************************************************
|
6
|
+
*
|
7
|
+
* Type definitions
|
8
|
+
*
|
9
|
+
********************************************************************/
|
10
|
+
|
11
|
+
typedef struct dheap_struct dheap_t;
|
12
|
+
typedef struct dheap_entry ENTRY;
|
13
|
+
|
14
|
+
// TODO: convert SCORE to a union, and use an ENTRY flag for its type
|
15
|
+
typedef long double SCORE;
|
16
|
+
|
17
|
+
#if LDBL_MANT_DIG < SIZEOF_UNSIGNED_LONG_LONG * 8
|
18
|
+
#error 'unsigned long long' must fit into 'long double' mantissa
|
19
|
+
#endif
|
20
|
+
|
21
|
+
// TODO: test this code on a 32 bit system (it MUST have some bugs!)
|
22
|
+
#if SIZEOF_UNSIGNED_LONG_LONG * 8 != 64
|
23
|
+
#error 'unsigned long long' must be 64bits
|
24
|
+
#endif
|
25
|
+
|
26
|
+
/********************************************************************
|
27
|
+
*
|
28
|
+
* Struct definitions
|
29
|
+
*
|
30
|
+
********************************************************************/
|
31
|
+
|
32
|
+
struct dheap_struct {
|
33
|
+
int d;
|
34
|
+
long size;
|
35
|
+
long capa;
|
36
|
+
ENTRY *entries;
|
37
|
+
};
|
38
|
+
|
39
|
+
struct dheap_entry {
|
40
|
+
SCORE score;
|
41
|
+
VALUE value;
|
42
|
+
};
|
43
|
+
|
44
|
+
/********************************************************************
|
45
|
+
*
|
46
|
+
* Constant definitions
|
47
|
+
*
|
48
|
+
********************************************************************/
|
49
|
+
|
50
|
+
#define DHEAP_DEFAULT_D 4
|
51
|
+
#define DHEAP_MAX_D INT_MAX
|
52
|
+
|
53
|
+
// sizeof(ENTRY) => 32 bytes
|
54
|
+
// one kilobyte = 32 * 32 bytes
|
55
|
+
#define DHEAP_DEFAULT_CAPA 32
|
56
|
+
#define DHEAP_MAX_CAPA (LONG_MAX / (int)sizeof(ENTRY))
|
57
|
+
#define DHEAP_CAPA_INCR_MAX (10 * 1024 * 1024 / (int)sizeof(ENTRY))
|
58
|
+
|
59
|
+
static ID id_cmp; // <=>
|
60
|
+
static ID id_abs; // abs
|
61
|
+
static ID id_lshift; // <<
|
62
|
+
static ID id_unary_minus; // -@
|
63
|
+
static const ENTRY EmptyDheapEntry; // 0 value for safety overwrite after pop
|
64
|
+
static const rb_data_type_t dheap_data_type;
|
65
|
+
|
66
|
+
/********************************************************************
|
67
|
+
*
|
68
|
+
* SCORE: casting to and from VALUE
|
69
|
+
* adapted from similar methods in ruby's object.c
|
70
|
+
*
|
71
|
+
********************************************************************/
|
72
|
+
|
73
|
+
// ruby doesn't have a LDBL2NUM. :(
|
74
|
+
// So this only accomplishes a subset of what that ought to do.
|
75
|
+
static inline VALUE
|
76
|
+
SCORE2NUM(SCORE s)
|
77
|
+
{
|
78
|
+
if (floorl((long double) s) == s) {
|
79
|
+
if (s < 0) {
|
80
|
+
unsigned long long ull = (unsigned long long)(-s);
|
81
|
+
return rb_funcall(ULL2NUM(ull), id_unary_minus, 0, Qundef);
|
82
|
+
}
|
83
|
+
return ULL2NUM((unsigned long long)(s));
|
32
84
|
}
|
85
|
+
return rb_float_new((double)(s));
|
86
|
+
}
|
33
87
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
88
|
+
static inline SCORE
|
89
|
+
FIX2SCORE(VALUE x)
|
90
|
+
{
|
91
|
+
return (long double)FIX2LONG(x);
|
92
|
+
}
|
93
|
+
|
94
|
+
// We could translate a much wider range of values to long double by
|
95
|
+
// implementing a new `rb_big2ldbl(x)` function. But requires reaching into
|
96
|
+
// T_BIGNUM internals.
|
97
|
+
static inline long double
|
98
|
+
BIG2SCORE(VALUE x)
|
99
|
+
{
|
100
|
+
if (RBIGNUM_POSITIVE_P(x)) {
|
101
|
+
unsigned long long ull = rb_big2ull(x);
|
102
|
+
return (long double)ull;
|
103
|
+
} else {
|
104
|
+
unsigned long long ull;
|
105
|
+
long double ldbl;
|
106
|
+
x = rb_funcall(x, id_abs, 0, Qundef);
|
107
|
+
ull = rb_big2ull(x);
|
108
|
+
ldbl = (long double) ull;
|
109
|
+
return -ldbl;
|
40
110
|
}
|
111
|
+
}
|
41
112
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
\
|
48
|
-
VALUE sift_value = DHEAP_VALUE(heap_array, sift_index); \
|
49
|
-
VALUE sift_score = DHEAP_SCORE(heap_array, sift_index);
|
113
|
+
static inline SCORE
|
114
|
+
INT2SCORE(VALUE x)
|
115
|
+
{
|
116
|
+
return (FIXNUM_P(x) ? FIX2SCORE(x) : BIG2SCORE(x));
|
117
|
+
}
|
50
118
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
VALUE parent_score = DHEAP_SCORE(heap_array, parent_index);
|
119
|
+
static inline SCORE
|
120
|
+
NUM2SCORE(VALUE x)
|
121
|
+
{
|
122
|
+
return (FIXNUM_P(x) ? FIX2SCORE(x) :
|
123
|
+
RB_TYPE_P(x, T_BIGNUM) ? BIG2SCORE(x) :
|
124
|
+
(Check_Type(x, T_FLOAT), (long double)RFLOAT_VALUE(x)));
|
125
|
+
}
|
59
126
|
|
60
|
-
|
61
|
-
|
127
|
+
static inline long double
|
128
|
+
RAT2SCORE(VALUE x)
|
129
|
+
{
|
130
|
+
VALUE num = rb_rational_num(x);
|
131
|
+
VALUE den = rb_rational_den(x);
|
132
|
+
return NUM2SCORE(num) / NUM2SCORE(den);
|
133
|
+
}
|
62
134
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
135
|
+
/*
|
136
|
+
* Convert both T_FIXNUM and T_FLOAT (and sometimes T_BIGNUM, T_RATIONAL,
|
137
|
+
* String, etc) to SCORE
|
138
|
+
* * with no loss of precision (where possible for Integer and Float),
|
139
|
+
* * raises an exception if
|
140
|
+
* * a positive integer is too large for unsigned long long (should be 64bit)
|
141
|
+
* * a negative integer is too small for signed long long (should be 64bit)
|
142
|
+
* * reduced to long double (should be 80 or 128 bit) if it is Rational
|
143
|
+
* * reduced to double precision if the value is convertable by Float(x)
|
144
|
+
*/
|
145
|
+
static inline SCORE
|
146
|
+
VAL2SCORE(VALUE score)
|
147
|
+
{
|
148
|
+
// assert that long double can hold 'unsigned long long':
|
149
|
+
// static_assert(sizeof(unsigned long long) * 8 <= LDBL_MANT_DIG);
|
150
|
+
// assert that long double can hold T_FLOAT
|
151
|
+
// static_assert(sizeof(double) <= sizeof(long double));
|
152
|
+
switch (TYPE(score)) {
|
153
|
+
case T_FIXNUM:
|
154
|
+
return FIX2SCORE(score);
|
155
|
+
case T_BIGNUM:
|
156
|
+
return BIG2SCORE(score);
|
157
|
+
case T_RATIONAL:
|
158
|
+
return RAT2SCORE(score);
|
159
|
+
default:
|
160
|
+
return (long double)(NUM2DBL(rb_Float(score)));
|
67
161
|
}
|
68
|
-
debug(rb_sprintf("sifted (%"PRIsVALUE", %d, %ld)", heap_array, d, sift_index));
|
69
|
-
return LONG2NUM(sift_index);
|
70
162
|
}
|
71
163
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
if (last_index < sibling_index) break;
|
90
|
-
|
91
|
-
VALUE sibling_score = DHEAP_SCORE(heap_array, sibling_index);
|
92
|
-
|
93
|
-
if (CMP_LT(sibling_score, child_score)) {
|
94
|
-
child_score = sibling_score;
|
95
|
-
child_index = sibling_index;
|
96
|
-
}
|
97
|
-
}
|
164
|
+
/********************************************************************
|
165
|
+
*
|
166
|
+
* DHeap ENTRY accessors
|
167
|
+
*
|
168
|
+
********************************************************************/
|
169
|
+
|
170
|
+
#define DHEAP_SCORE(heap, idx) ((heap)->entries[idx].score)
|
171
|
+
#define DHEAP_VALUE(heap, idx) ((heap)->entries[idx].value)
|
172
|
+
|
173
|
+
static inline VALUE
|
174
|
+
DHEAP_ENTRY_ARY(dheap_t *heap, long idx)
|
175
|
+
{
|
176
|
+
if (idx < 0 || heap->size <= idx) { return Qnil; }
|
177
|
+
return rb_ary_new_from_args(2,
|
178
|
+
DHEAP_VALUE(heap, 0),
|
179
|
+
SCORE2NUM(DHEAP_SCORE(heap, 0)));
|
180
|
+
}
|
98
181
|
|
99
|
-
|
100
|
-
|
182
|
+
/********************************************************************
|
183
|
+
*
|
184
|
+
* DHeap index math
|
185
|
+
*
|
186
|
+
********************************************************************/
|
187
|
+
|
188
|
+
#define DHEAP_IDX_LAST(heap) ((heap)->size - 1)
|
189
|
+
#define DHEAP_IDX_PARENT(heap, idx) (((idx) - 1) / (heap)->d)
|
190
|
+
#define DHEAP_IDX_CHILD_0(heap, idx) (((idx) * (heap)->d) + 1)
|
191
|
+
#define DHEAP_IDX_CHILD_D(heap, idx) (((idx) * (heap)->d) + (heap)->d)
|
192
|
+
|
193
|
+
#ifdef __D_HEAP_DEBUG
|
194
|
+
#define ASSERT_DHEAP_IDX_OK(heap, index) do { \
|
195
|
+
if (index < 0) { \
|
196
|
+
rb_raise(rb_eIndexError, "DHeap index %ld too small", index); \
|
197
|
+
} \
|
198
|
+
else if (DHEAP_IDX_LAST(heap) < index) { \
|
199
|
+
rb_raise(rb_eIndexError, "DHeap index %ld too large", index); \
|
200
|
+
} \
|
201
|
+
} while (0)
|
202
|
+
#else
|
203
|
+
#define ASSERT_DHEAP_IDX_OK(heap, index)
|
204
|
+
#endif
|
205
|
+
|
206
|
+
/********************************************************************
|
207
|
+
*
|
208
|
+
* rb_data_type_t definitions
|
209
|
+
*
|
210
|
+
********************************************************************/
|
101
211
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
212
|
+
#ifdef HAVE_RB_GC_MARK_MOVABLE
|
213
|
+
static void
|
214
|
+
dheap_compact(void *ptr)
|
215
|
+
{
|
216
|
+
dheap_t *heap = ptr;
|
217
|
+
for (long i = 0; i < heap->size; ++i) {
|
218
|
+
if (DHEAP_VALUE(heap, i))
|
219
|
+
rb_gc_location(DHEAP_VALUE(heap, i));
|
106
220
|
}
|
107
|
-
debug(rb_sprintf("sifted (%"PRIsVALUE", %d, %ld)", heap_array, d, sift_index));
|
108
|
-
return LONG2NUM(sift_index);
|
109
221
|
}
|
222
|
+
#else
|
223
|
+
#define rb_gc_mark_movable(x) rb_gc_mark(x)
|
224
|
+
#endif
|
110
225
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
226
|
+
static void
|
227
|
+
dheap_mark(void *ptr)
|
228
|
+
{
|
229
|
+
dheap_t *heap = ptr;
|
230
|
+
for (long i = 0; i < heap->size; ++i) {
|
231
|
+
if (DHEAP_VALUE(heap, i))
|
232
|
+
rb_gc_mark_movable(DHEAP_VALUE(heap,i));
|
233
|
+
}
|
234
|
+
}
|
115
235
|
|
116
|
-
|
117
|
-
*
|
118
|
-
|
236
|
+
static void
|
237
|
+
dheap_free(void *ptr)
|
238
|
+
{
|
239
|
+
dheap_t *heap = ptr;
|
240
|
+
heap->size = 0;
|
241
|
+
if (heap->entries) {
|
242
|
+
xfree(heap->entries);
|
243
|
+
heap->entries = NULL;
|
244
|
+
}
|
245
|
+
heap->capa = 0;
|
246
|
+
xfree(ptr);
|
247
|
+
}
|
248
|
+
|
249
|
+
static size_t
|
250
|
+
dheap_memsize(const void *ptr)
|
251
|
+
{
|
252
|
+
const dheap_t *heap = ptr;
|
253
|
+
size_t size = 0;
|
254
|
+
size += sizeof(*heap);
|
255
|
+
size += sizeof(ENTRY) * heap->capa;
|
256
|
+
return size;
|
257
|
+
}
|
258
|
+
|
259
|
+
|
260
|
+
static const rb_data_type_t dheap_data_type = {
|
261
|
+
"DHeap",
|
262
|
+
{
|
263
|
+
(void (*)(void*))dheap_mark,
|
264
|
+
(void (*)(void*))dheap_free,
|
265
|
+
(size_t (*)(const void *))dheap_memsize,
|
266
|
+
#ifdef HAVE_RB_GC_MARK_MOVABLE
|
267
|
+
(void (*)(void*))dheap_compact, {0}
|
268
|
+
#else
|
269
|
+
{0}
|
270
|
+
#endif
|
271
|
+
},
|
272
|
+
0, 0,
|
273
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
274
|
+
};
|
275
|
+
|
276
|
+
/********************************************************************
|
119
277
|
*
|
120
|
-
*
|
121
|
-
*
|
122
|
-
* values in every odd numbered index. The array is flat, not an array of
|
123
|
-
* length=2 arrays.
|
278
|
+
* DHeap comparisons
|
279
|
+
* TODO: bring back comparisons for score types other than `long double`.
|
124
280
|
*
|
125
|
-
|
281
|
+
********************************************************************/
|
282
|
+
|
283
|
+
#define CMP_LT(a, b) ((a) < (b))
|
284
|
+
#define CMP_LTE(a, b) ((a) <= (b))
|
285
|
+
|
286
|
+
/* #ifdef ORIG_SCORE_CMP_CODE */
|
287
|
+
|
288
|
+
/* #define CMP_LT(a, b) (optimized_cmp(a, b) < 0) */
|
289
|
+
/* #define CMP_LTE(a, b) (optimized_cmp(a, b) <= 0) */
|
290
|
+
|
291
|
+
/* // from internal/compar.h */
|
292
|
+
/* #define STRING_P(s) (RB_TYPE_P((s), T_STRING) && CLASS_OF(s) == rb_cString) */
|
293
|
+
/*
|
294
|
+
* short-circuit evaluation for a few basic types.
|
126
295
|
*
|
127
|
-
*
|
128
|
-
*
|
129
|
-
* @param sift_index [Integer] the index to start sifting from
|
130
|
-
* @return [Integer] the new index for the object that starts at +sift_index+.
|
296
|
+
* Only Integer, Float, and String are optimized,
|
297
|
+
* and only when both arguments are the same type.
|
131
298
|
*/
|
299
|
+
/* static inline int */
|
300
|
+
/* optimized_cmp(SCORE a, SCORE b) { */
|
301
|
+
/* if (a == b) // Fixnum equality and object equality */
|
302
|
+
/* return 0; */
|
303
|
+
/* if (FIXNUM_P(a) && FIXNUM_P(b)) */
|
304
|
+
/* return (FIX2LONG(a) < FIX2LONG(b)) ? -1 : 1; */
|
305
|
+
/* if (RB_FLOAT_TYPE_P(a) && RB_FLOAT_TYPE_P(b)) */
|
306
|
+
/* { */
|
307
|
+
/* double x, y; */
|
308
|
+
/* x = RFLOAT_VALUE(a); */
|
309
|
+
/* y = RFLOAT_VALUE(b); */
|
310
|
+
/* if (isnan(x) || isnan(y)) rb_cmperr(a, b); // raise ArgumentError */
|
311
|
+
/* return (x < y) ? -1 : ((x == y) ? 0 : 1); */
|
312
|
+
/* } */
|
313
|
+
/* if (RB_TYPE_P(a, T_BIGNUM) && RB_TYPE_P(b, T_BIGNUM)) */
|
314
|
+
/* return FIX2INT(rb_big_cmp(a, b)); */
|
315
|
+
/* if (STRING_P(a) && STRING_P(b)) */
|
316
|
+
/* return rb_str_cmp(a, b); */
|
317
|
+
|
318
|
+
/* // give up on an optimized version and just call (a <=> b) */
|
319
|
+
/* return rb_cmpint(rb_funcallv(a, id_cmp, 1, &b), a, b); */
|
320
|
+
/* } */
|
321
|
+
|
322
|
+
/* #endif */
|
323
|
+
|
324
|
+
/********************************************************************
|
325
|
+
*
|
326
|
+
* DHeap allocation and initialization and resizing
|
327
|
+
*
|
328
|
+
********************************************************************/
|
329
|
+
|
132
330
|
static VALUE
|
133
|
-
|
134
|
-
|
135
|
-
|
331
|
+
dheap_s_alloc(VALUE klass)
|
332
|
+
{
|
333
|
+
VALUE obj;
|
334
|
+
dheap_t *heap;
|
335
|
+
|
336
|
+
// TypedData_Make_Struct uses a non-std "statement expression"
|
337
|
+
#pragma GCC diagnostic push
|
338
|
+
#pragma GCC diagnostic ignored "-Wpedantic"
|
339
|
+
obj = TypedData_Make_Struct(klass, dheap_t, &dheap_data_type, heap);
|
340
|
+
#pragma GCC diagnostic pop
|
341
|
+
heap->d = DHEAP_DEFAULT_D;
|
342
|
+
|
343
|
+
heap->size = 0;
|
344
|
+
heap->capa = 0;
|
345
|
+
heap->entries = NULL;
|
346
|
+
|
347
|
+
return obj;
|
136
348
|
}
|
137
349
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
*
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
*
|
350
|
+
static inline dheap_t *
|
351
|
+
get_dheap_struct(VALUE self)
|
352
|
+
{
|
353
|
+
dheap_t *heap;
|
354
|
+
TypedData_Get_Struct(self, dheap_t, &dheap_data_type, heap);
|
355
|
+
return heap;
|
356
|
+
}
|
357
|
+
|
358
|
+
void
|
359
|
+
dheap_set_capa(dheap_t *heap, long new_capa)
|
360
|
+
{
|
361
|
+
// Do nothing if we already have the capacity or are resizing too small
|
362
|
+
if (new_capa <= heap->capa || new_capa <= heap->size) return;
|
363
|
+
|
364
|
+
// allocate
|
365
|
+
if (heap->entries) {
|
366
|
+
RB_REALLOC_N(heap->entries, ENTRY, new_capa);
|
367
|
+
} else {
|
368
|
+
heap->entries = RB_ZALLOC_N(ENTRY, new_capa);
|
369
|
+
}
|
370
|
+
heap->capa = new_capa;
|
371
|
+
}
|
372
|
+
|
373
|
+
static void
|
374
|
+
dheap_ensure_room_for_push(dheap_t *heap, long incr_by)
|
375
|
+
{
|
376
|
+
long new_size = heap->size + incr_by;
|
377
|
+
|
378
|
+
// check for overflow of new_size
|
379
|
+
if (DHEAP_MAX_CAPA - incr_by < heap->size)
|
380
|
+
rb_raise(rb_eIndexError, "index %ld too big", new_size);
|
381
|
+
|
382
|
+
// if it existing capacity is too small
|
383
|
+
if (heap->capa < new_size) {
|
384
|
+
// double it...
|
385
|
+
long new_capa = new_size * 2;
|
386
|
+
if (DHEAP_CAPA_INCR_MAX < new_size)
|
387
|
+
new_size = new_size + DHEAP_CAPA_INCR_MAX;
|
388
|
+
// check for overflow of new_capa
|
389
|
+
if (DHEAP_MAX_CAPA / 2 < new_size) new_capa = DHEAP_MAX_CAPA;
|
390
|
+
// cap max incr_by
|
391
|
+
if (heap->capa + DHEAP_CAPA_INCR_MAX < new_capa)
|
392
|
+
new_capa = heap->capa + DHEAP_CAPA_INCR_MAX;
|
393
|
+
|
394
|
+
dheap_set_capa(heap, new_capa);
|
395
|
+
}
|
396
|
+
}
|
397
|
+
|
398
|
+
static inline int
|
399
|
+
dheap_value_to_int_d(VALUE num)
|
400
|
+
{
|
401
|
+
int d = NUM2INT(num);
|
402
|
+
if (d < 2) {
|
403
|
+
rb_raise(rb_eArgError, "DHeap d=%u is too small", d);
|
404
|
+
}
|
405
|
+
if (d > DHEAP_MAX_D) {
|
406
|
+
rb_raise(rb_eArgError, "DHeap d=%u is too large", d);
|
407
|
+
}
|
408
|
+
return d;
|
409
|
+
}
|
410
|
+
|
411
|
+
static inline long
|
412
|
+
dheap_value_to_long_capa(VALUE num)
|
413
|
+
{
|
414
|
+
long capa = NUM2LONG(num);
|
415
|
+
if (capa < 1) {
|
416
|
+
rb_raise(rb_eArgError, "DHeap capa=%lu must be positive", capa);
|
417
|
+
}
|
418
|
+
return capa;
|
419
|
+
}
|
420
|
+
|
421
|
+
static VALUE
|
422
|
+
dheap_initialize(VALUE self, VALUE d, VALUE capa) {
|
423
|
+
dheap_t *heap = get_dheap_struct(self);
|
424
|
+
|
425
|
+
if(heap->entries || heap->size || heap->capa)
|
426
|
+
rb_raise(rb_eScriptError, "DHeap already initialized.");
|
427
|
+
|
428
|
+
heap->d = dheap_value_to_int_d(d);
|
429
|
+
dheap_set_capa(heap, dheap_value_to_long_capa(capa));
|
430
|
+
|
431
|
+
return self;
|
432
|
+
}
|
433
|
+
|
434
|
+
/* @!visibility private */
|
435
|
+
static VALUE
|
436
|
+
dheap_initialize_copy(VALUE copy, VALUE orig)
|
437
|
+
{
|
438
|
+
dheap_t *heap_copy;
|
439
|
+
dheap_t *heap_orig = get_dheap_struct(orig);
|
440
|
+
|
441
|
+
rb_check_frozen(copy);
|
442
|
+
TypedData_Get_Struct(copy, dheap_t, &dheap_data_type, heap_copy);
|
443
|
+
|
444
|
+
heap_copy->d = heap_orig->d;
|
445
|
+
|
446
|
+
dheap_set_capa(heap_copy, heap_orig->capa);
|
447
|
+
heap_copy->size = heap_orig->size;
|
448
|
+
if (heap_copy->size)
|
449
|
+
MEMCPY(heap_copy->entries, heap_orig->entries, ENTRY, heap_orig->size);
|
450
|
+
|
451
|
+
return copy;
|
452
|
+
}
|
453
|
+
|
454
|
+
/********************************************************************
|
148
455
|
*
|
149
|
-
*
|
456
|
+
* DHeap sift up/down
|
150
457
|
*
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
*
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
458
|
+
********************************************************************/
|
459
|
+
|
460
|
+
VALUE
|
461
|
+
dheap_sift_up(dheap_t *heap, long index) {
|
462
|
+
ENTRY entry = heap->entries[index];
|
463
|
+
|
464
|
+
ASSERT_DHEAP_IDX_OK(heap, index);
|
465
|
+
|
466
|
+
// sift it up to where it belongs
|
467
|
+
for (long parent_index; 0 < index; index = parent_index) {
|
468
|
+
/* debug(rb_sprintf("sift up(%"PRIsVALUE", %d, %ld)", heap->values, heap->d, index)); */
|
469
|
+
parent_index = DHEAP_IDX_PARENT(heap, index);
|
470
|
+
|
471
|
+
// parent is smaller: heap is restored
|
472
|
+
if (CMP_LTE(DHEAP_SCORE(heap, parent_index), entry.score)) break;
|
473
|
+
|
474
|
+
// parent is larger: swap and continue sifting up
|
475
|
+
heap->entries[index] = heap->entries[parent_index];
|
476
|
+
}
|
477
|
+
heap->entries[index] = entry;
|
478
|
+
/* debug(rb_sprintf("sifted (%"PRIsVALUE", %d, %ld)", heap->values, heap->d, index)); */
|
479
|
+
return LONG2NUM(index);
|
160
480
|
}
|
161
481
|
|
162
482
|
/*
|
163
|
-
*
|
164
|
-
* Initialize a _d_-ary min-heap.
|
165
|
-
*
|
166
|
-
* @param d [Integer] maximum number of children per parent
|
483
|
+
* this is a tiny bit more complicated than the binary heap version
|
167
484
|
*/
|
168
|
-
static
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
if (
|
173
|
-
|
485
|
+
static inline long
|
486
|
+
dheap_find_min_child(dheap_t *heap, long parent, long last_index) {
|
487
|
+
long min_child = DHEAP_IDX_CHILD_0(heap, parent);
|
488
|
+
long last_sib = DHEAP_IDX_CHILD_D(heap, parent);
|
489
|
+
if (last_index < last_sib) last_sib = last_index;
|
490
|
+
|
491
|
+
for (long sibidx = min_child + 1; sibidx <= last_sib; ++sibidx) {
|
492
|
+
if (CMP_LT(DHEAP_SCORE(heap, sibidx),
|
493
|
+
DHEAP_SCORE(heap, min_child))) {
|
494
|
+
min_child = sibidx;
|
495
|
+
}
|
174
496
|
}
|
175
|
-
|
176
|
-
rb_ivar_set(self, id_ivar_d, INT2FIX(d));
|
177
|
-
rb_ivar_set(self, id_ivar_a, rb_ary_new());
|
178
|
-
return self;
|
497
|
+
return min_child;
|
179
498
|
}
|
180
499
|
|
500
|
+
void
|
501
|
+
dheap_sift_down(dheap_t *heap, long index, long last_index) {
|
502
|
+
if (last_index < 1 || DHEAP_IDX_PARENT(heap, last_index) < index) {
|
503
|
+
// short-circuit: no chance for a child
|
504
|
+
return;
|
505
|
+
|
506
|
+
} else {
|
507
|
+
ENTRY entry = heap->entries[index];
|
508
|
+
|
509
|
+
long last_parent = DHEAP_IDX_PARENT(heap, last_index);
|
510
|
+
|
511
|
+
ASSERT_DHEAP_IDX_OK(heap, index);
|
512
|
+
|
513
|
+
// iteratively sift it down to where it belongs
|
514
|
+
while (index <= last_parent) {
|
515
|
+
// find min child
|
516
|
+
long min_child = dheap_find_min_child(heap, index, last_index);
|
517
|
+
|
518
|
+
// child is larger: heap is restored
|
519
|
+
if (CMP_LTE(entry.score, DHEAP_SCORE(heap, min_child))) break;
|
520
|
+
|
521
|
+
// child is smaller: swap and continue sifting down
|
522
|
+
heap->entries[index] = heap->entries[min_child];
|
523
|
+
index = min_child;
|
524
|
+
}
|
525
|
+
heap->entries[index] = entry;
|
526
|
+
// debug(rb_sprintf("sifted (%"PRIsVALUE", %d, %ld)", heap->values, heap->d, index));
|
527
|
+
}
|
528
|
+
}
|
529
|
+
|
530
|
+
/********************************************************************
|
531
|
+
*
|
532
|
+
* DHeap attributes
|
533
|
+
*
|
534
|
+
********************************************************************/
|
535
|
+
|
181
536
|
/*
|
182
537
|
* @return [Integer] the number of elements in the heap
|
183
538
|
*/
|
184
|
-
static VALUE
|
185
|
-
|
186
|
-
|
187
|
-
|
539
|
+
static VALUE
|
540
|
+
dheap_size(VALUE self)
|
541
|
+
{
|
542
|
+
dheap_t *heap = get_dheap_struct(self);
|
543
|
+
return LONG2NUM(heap->size);
|
188
544
|
}
|
189
545
|
|
190
546
|
/*
|
191
|
-
* @return [Boolean]
|
547
|
+
* @return [Boolean] if the heap is empty
|
192
548
|
*/
|
193
|
-
static VALUE
|
194
|
-
|
195
|
-
|
196
|
-
|
549
|
+
static VALUE
|
550
|
+
dheap_empty_p(VALUE self)
|
551
|
+
{
|
552
|
+
dheap_t *heap = get_dheap_struct(self);
|
553
|
+
return heap->size ? Qfalse : Qtrue;
|
197
554
|
}
|
198
555
|
|
199
556
|
/*
|
200
557
|
* @return [Integer] the maximum number of children per parent
|
201
558
|
*/
|
202
|
-
static VALUE
|
559
|
+
static VALUE
|
560
|
+
dheap_attr_d(VALUE self)
|
561
|
+
{
|
562
|
+
dheap_t *heap = get_dheap_struct(self);
|
563
|
+
return INT2FIX(heap->d);
|
564
|
+
}
|
565
|
+
|
566
|
+
/********************************************************************
|
567
|
+
*
|
568
|
+
* DHeap push
|
569
|
+
*
|
570
|
+
********************************************************************/
|
571
|
+
|
572
|
+
static inline void
|
573
|
+
dheap_push_entry(dheap_t *heap, ENTRY *entry) {
|
574
|
+
dheap_ensure_room_for_push(heap, 1);
|
575
|
+
heap->entries[heap->size] = *entry;
|
576
|
+
++heap->size;
|
577
|
+
dheap_sift_up(heap, heap->size - 1);
|
578
|
+
}
|
203
579
|
|
204
580
|
/*
|
205
|
-
*
|
206
|
-
*
|
581
|
+
* Inserts a value into the heap, using a score to determine sort-order.
|
582
|
+
*
|
583
|
+
* Score comes first, as an analogy with the +Array#insert+ index.
|
584
|
+
*
|
585
|
+
* Time complexity: <b>O(log n / log d)</b> <i>(worst-case)</i>
|
586
|
+
*
|
587
|
+
* @param score [Integer,Float,#to_f] a score to compare against other scores.
|
588
|
+
* @param value [Object] an object that is associated with the score.
|
207
589
|
*
|
208
590
|
* @return [self]
|
209
591
|
*/
|
210
592
|
static VALUE
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
return rb_call_super(0, NULL);
|
216
|
-
}
|
593
|
+
dheap_insert(VALUE self, VALUE score, VALUE value) {
|
594
|
+
ENTRY entry;
|
595
|
+
dheap_t *heap = get_dheap_struct(self);
|
596
|
+
rb_check_frozen(self);
|
217
597
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
return dheap_ary_sift_up(ary, d, last_index);
|
598
|
+
entry.score = VAL2SCORE(score);
|
599
|
+
entry.value = value;
|
600
|
+
dheap_push_entry(heap, &entry);
|
601
|
+
|
602
|
+
return self;
|
224
603
|
}
|
225
604
|
|
226
605
|
/*
|
227
|
-
* @overload push(
|
606
|
+
* @overload push(value, score = value)
|
228
607
|
*
|
229
608
|
* Push a value onto heap, using a score to determine sort-order.
|
230
609
|
*
|
231
|
-
*
|
232
|
-
*
|
610
|
+
* Value comes first because the separate score is optional, and because it feels
|
611
|
+
* like a more natural variation on +Array#push+ or +Queue#enq+. If a score
|
612
|
+
* isn't provided, the value must be an Integer or can be cast with
|
613
|
+
* +Float(value)+.
|
233
614
|
*
|
234
615
|
* Time complexity: <b>O(log n / log d)</b> <i>(worst-case)</i>
|
235
616
|
*
|
236
|
-
* @param score [#<=>] a value that can be compared to other scores.
|
237
617
|
* @param value [Object] an object that is associated with the score.
|
618
|
+
* @param score [Integer,Float,#to_f] a score to compare against other scores.
|
238
619
|
*
|
239
|
-
* @return [
|
620
|
+
* @return [self]
|
240
621
|
*/
|
241
622
|
static VALUE
|
242
623
|
dheap_push(int argc, VALUE *argv, VALUE self) {
|
243
|
-
|
244
|
-
|
245
|
-
|
624
|
+
dheap_t *heap = get_dheap_struct(self);
|
625
|
+
ENTRY entry;
|
626
|
+
rb_check_frozen(self);
|
246
627
|
|
247
|
-
|
248
|
-
|
249
|
-
|
628
|
+
rb_check_arity(argc, 1, 2);
|
629
|
+
entry.value = argv[0];
|
630
|
+
entry.score = VAL2SCORE(argc < 2 ? entry.value : argv[1]);
|
631
|
+
dheap_push_entry(heap, &entry);
|
250
632
|
|
251
|
-
return
|
633
|
+
return self;
|
252
634
|
}
|
253
635
|
|
254
636
|
/*
|
255
|
-
* Pushes a
|
637
|
+
* Pushes a value onto the heap.
|
256
638
|
*
|
257
|
-
* The
|
639
|
+
* The score will be derived from the value, by using the value itself if it is
|
640
|
+
* an Integer, otherwise by casting it with +Float(value)+.
|
258
641
|
*
|
259
642
|
* Time complexity: <b>O(log n / log d)</b> <i>(worst-case)</i>
|
260
643
|
*
|
261
|
-
* @param value [
|
644
|
+
* @param value [Integer,#to_f] a value with an intrinsic numeric score
|
262
645
|
* @return [self]
|
263
646
|
*/
|
264
647
|
static VALUE
|
265
648
|
dheap_left_shift(VALUE self, VALUE value) {
|
266
|
-
|
649
|
+
dheap_t *heap = get_dheap_struct(self);
|
650
|
+
ENTRY entry;
|
651
|
+
rb_check_frozen(self);
|
652
|
+
|
653
|
+
entry.score = VAL2SCORE(value);
|
654
|
+
entry.value = value;
|
655
|
+
dheap_push_entry(heap, &entry);
|
656
|
+
|
267
657
|
return self;
|
268
658
|
}
|
269
659
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
660
|
+
/********************************************************************
|
661
|
+
*
|
662
|
+
* DHeap pop and peek
|
663
|
+
*
|
664
|
+
********************************************************************/
|
665
|
+
|
666
|
+
static inline void
|
667
|
+
dheap_del0(dheap_t *heap)
|
668
|
+
{
|
669
|
+
if (0 < --heap->size) {
|
670
|
+
heap->entries[0] = heap->entries[heap->size];
|
671
|
+
heap->entries[heap->size] = EmptyDheapEntry; // unnecessary to zero?
|
672
|
+
dheap_sift_down(heap, 0, heap->size - 1);
|
673
|
+
}
|
674
|
+
}
|
675
|
+
|
676
|
+
static inline VALUE
|
677
|
+
dheap_pop0(dheap_t *heap)
|
678
|
+
{
|
679
|
+
VALUE popped = DHEAP_VALUE(heap, 0);
|
680
|
+
dheap_del0(heap);
|
681
|
+
return popped;
|
682
|
+
}
|
683
|
+
|
684
|
+
/*
|
685
|
+
* Returns the next value on the heap, and its score, without popping it
|
686
|
+
*
|
687
|
+
* Time complexity: <b>O(1)</b> <i>(worst-case)</i>
|
688
|
+
* @return [nil,Array<(Object, Numeric)>] the next value and its score
|
689
|
+
*
|
690
|
+
* @see #peek
|
691
|
+
* @see #peek_score
|
692
|
+
*/
|
693
|
+
static VALUE
|
694
|
+
dheap_peek_with_score(VALUE self)
|
695
|
+
{
|
696
|
+
dheap_t *heap = get_dheap_struct(self);
|
697
|
+
return DHEAP_ENTRY_ARY(heap, 0);
|
698
|
+
}
|
274
699
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
700
|
+
/*
|
701
|
+
* Returns the next score on the heap, without the value and without popping it.
|
702
|
+
*
|
703
|
+
* Time complexity: <b>O(1)</b> <i>(worst-case)</i>
|
704
|
+
* @return [nil, Numeric] the next score, if there is one
|
705
|
+
*
|
706
|
+
* @see #peek
|
707
|
+
* @see #peek_with_score
|
708
|
+
*/
|
709
|
+
static VALUE
|
710
|
+
dheap_peek_score(VALUE self)
|
711
|
+
{
|
712
|
+
dheap_t *heap = get_dheap_struct(self);
|
713
|
+
if (DHEAP_IDX_LAST(heap) < 0) return Qnil;
|
714
|
+
return SCORE2NUM(DHEAP_SCORE(heap, 0));
|
715
|
+
}
|
282
716
|
|
283
717
|
/*
|
284
718
|
* Returns the next value on the heap to be popped without popping it.
|
285
719
|
*
|
286
720
|
* Time complexity: <b>O(1)</b> <i>(worst-case)</i>
|
287
|
-
* @return [Object] the next value to be popped without popping it.
|
721
|
+
* @return [nil, Object] the next value to be popped without popping it.
|
722
|
+
*
|
723
|
+
* @see #peek_score
|
724
|
+
* @see #peek_with_score
|
288
725
|
*/
|
289
726
|
static VALUE
|
290
|
-
dheap_peek(VALUE self)
|
291
|
-
|
292
|
-
|
727
|
+
dheap_peek(VALUE self)
|
728
|
+
{
|
729
|
+
dheap_t *heap = get_dheap_struct(self);
|
730
|
+
return heap->size ? DHEAP_VALUE(heap, 0) : Qnil;
|
293
731
|
}
|
294
732
|
|
295
733
|
/*
|
296
734
|
* Pops the minimum value from the top of the heap
|
297
735
|
*
|
298
736
|
* Time complexity: <b>O(d log n / log d)</b> <i>(worst-case)</i>
|
737
|
+
*
|
738
|
+
* @return [Object] the value with the minimum score
|
739
|
+
*
|
740
|
+
* @see #peek
|
741
|
+
* @see #pop_lt
|
742
|
+
* @see #pop_lte
|
743
|
+
* @see #pop_with_score
|
299
744
|
*/
|
300
745
|
static VALUE
|
301
|
-
dheap_pop(VALUE self)
|
302
|
-
|
303
|
-
|
304
|
-
|
746
|
+
dheap_pop(VALUE self)
|
747
|
+
{
|
748
|
+
dheap_t *heap = get_dheap_struct(self);
|
749
|
+
rb_check_frozen(self);
|
750
|
+
return heap->size ? dheap_pop0(heap) : Qnil;
|
751
|
+
}
|
305
752
|
|
306
|
-
|
307
|
-
|
753
|
+
/*
|
754
|
+
* Pops the minimum value from the top of the heap, along with its score.
|
755
|
+
*
|
756
|
+
* Time complexity: <b>O(d log n / log d)</b> <i>(worst-case)</i>
|
757
|
+
*
|
758
|
+
* @return [nil,Array<(Object, Numeric)>] the next value and its score
|
759
|
+
*
|
760
|
+
* @see #pop
|
761
|
+
* @see #peek_with_score
|
762
|
+
*/
|
763
|
+
static VALUE
|
764
|
+
dheap_pop_with_score(VALUE self)
|
765
|
+
{
|
766
|
+
dheap_t *heap = get_dheap_struct(self);
|
767
|
+
VALUE ary = DHEAP_ENTRY_ARY(heap, 0);
|
768
|
+
rb_check_frozen(self);
|
769
|
+
if (ary != Qnil) { dheap_pop0(heap); }
|
770
|
+
return ary;
|
308
771
|
}
|
309
772
|
|
310
773
|
/*
|
311
774
|
* Pops the minimum value only if it is less than or equal to a max score.
|
312
775
|
*
|
313
|
-
* @param max_score [
|
776
|
+
* @param max_score [Integer,#to_f] the maximum score to be popped
|
777
|
+
*
|
778
|
+
* Time complexity: <b>O(d log n / log d)</b> <i>(worst-case)</i>
|
779
|
+
*
|
780
|
+
* @return [Object] the value with the minimum score
|
314
781
|
*
|
782
|
+
* @see #peek
|
315
783
|
* @see #pop
|
784
|
+
* @see #pop_lt
|
785
|
+
* @see #pop_all_below
|
316
786
|
*/
|
317
787
|
static VALUE
|
318
|
-
dheap_pop_lte(VALUE self, VALUE max_score)
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
DHEAP_Pop_SwapLastAndSiftDown(ary, dval, last_index, sift_value);
|
327
|
-
return pop_value;
|
788
|
+
dheap_pop_lte(VALUE self, VALUE max_score)
|
789
|
+
{
|
790
|
+
dheap_t *heap = get_dheap_struct(self);
|
791
|
+
rb_check_frozen(self);
|
792
|
+
if (heap->size <= 0) return Qnil;
|
793
|
+
if (!CMP_LTE(DHEAP_SCORE(heap, 0), VAL2SCORE(max_score))) return Qnil;
|
794
|
+
return dheap_pop0(heap);
|
328
795
|
}
|
329
796
|
|
330
797
|
/*
|
331
798
|
* Pops the minimum value only if it is less than a max score.
|
332
799
|
*
|
333
|
-
* @param max_score [
|
800
|
+
* @param max_score [Integer,#to_f] the maximum score to be popped
|
334
801
|
*
|
335
802
|
* Time complexity: <b>O(d log n / log d)</b> <i>(worst-case)</i>
|
803
|
+
*
|
804
|
+
* @return [Object] the value with the minimum score
|
805
|
+
*
|
806
|
+
* @see #peek
|
807
|
+
* @see #pop
|
808
|
+
* @see #pop_lte
|
809
|
+
* @see #pop_all_below
|
336
810
|
*/
|
337
811
|
static VALUE
|
338
|
-
dheap_pop_lt(VALUE self, VALUE max_score)
|
339
|
-
|
340
|
-
|
341
|
-
|
812
|
+
dheap_pop_lt(VALUE self, VALUE max_score)
|
813
|
+
{
|
814
|
+
dheap_t *heap = get_dheap_struct(self);
|
815
|
+
rb_check_frozen(self);
|
816
|
+
if (heap->size <= 0) return Qnil;
|
817
|
+
if (!CMP_LT(DHEAP_SCORE(heap, 0), VAL2SCORE(max_score))) return Qnil;
|
818
|
+
return dheap_pop0(heap);
|
819
|
+
}
|
342
820
|
|
343
|
-
|
344
|
-
|
821
|
+
#define DHEAP_PEEK_LT_P(heap, max_score) \
|
822
|
+
(heap->size && CMP_LT(DHEAP_SCORE(heap, 0), max_score))
|
345
823
|
|
346
|
-
|
347
|
-
|
824
|
+
static VALUE
|
825
|
+
dheap_pop_all_below0(dheap_t *heap, SCORE max_score, VALUE array)
|
826
|
+
{
|
827
|
+
if (!RTEST(array)) { array = rb_ary_new(); }
|
828
|
+
if (RB_TYPE_P(array, T_ARRAY)) {
|
829
|
+
while (DHEAP_PEEK_LT_P(heap, max_score)) {
|
830
|
+
rb_ary_push(array, dheap_pop0(heap));
|
831
|
+
}
|
832
|
+
} else {
|
833
|
+
while (DHEAP_PEEK_LT_P(heap, max_score)) {
|
834
|
+
rb_funcall(array, id_lshift, 1, dheap_pop0(heap));
|
835
|
+
}
|
836
|
+
}
|
837
|
+
return array;
|
348
838
|
}
|
349
839
|
|
350
|
-
|
351
|
-
|
840
|
+
/*
|
841
|
+
* @overload pop_all_below(max_score, receiver = [])
|
842
|
+
*
|
843
|
+
* Pops all value with score less than max score.
|
844
|
+
*
|
845
|
+
* Time complexity: <b>O(m * d log n / log d)</b>, <i>m = number popped</i>
|
846
|
+
*
|
847
|
+
* @param max_score [Integer,#to_f] the maximum score to be popped
|
848
|
+
* @param receiver [Array,#<<] object onto which the values will be pushed,
|
849
|
+
* in order by score.
|
850
|
+
*
|
851
|
+
* @return [Object] the object onto which the values were pushed
|
852
|
+
*
|
853
|
+
* @see #pop
|
854
|
+
* @see #pop_lt
|
855
|
+
*/
|
856
|
+
static VALUE
|
857
|
+
dheap_pop_all_below(int argc, VALUE *argv, VALUE self)
|
352
858
|
{
|
353
|
-
|
354
|
-
|
355
|
-
|
859
|
+
dheap_t *heap = get_dheap_struct(self);
|
860
|
+
SCORE max_score;
|
861
|
+
VALUE array;
|
862
|
+
rb_check_frozen(self);
|
863
|
+
rb_check_arity(argc, 1, 2);
|
864
|
+
max_score = VAL2SCORE(argv[0]);
|
865
|
+
if (argc == 1) {
|
866
|
+
array = rb_ary_new();
|
867
|
+
} else {
|
868
|
+
array = argv[1];
|
869
|
+
}
|
870
|
+
return dheap_pop_all_below0(heap, max_score, array);
|
871
|
+
}
|
356
872
|
|
357
|
-
|
358
|
-
|
359
|
-
|
873
|
+
/********************************************************************
|
874
|
+
*
|
875
|
+
* DHeap, misc methods
|
876
|
+
*
|
877
|
+
********************************************************************/
|
360
878
|
|
361
|
-
|
362
|
-
|
879
|
+
/*
|
880
|
+
* Clears all values from the heap, leaving it empty.
|
881
|
+
*
|
882
|
+
* @return [self]
|
883
|
+
*/
|
884
|
+
static VALUE
|
885
|
+
dheap_clear(VALUE self)
|
886
|
+
{
|
887
|
+
dheap_t *heap = get_dheap_struct(self);
|
888
|
+
rb_check_frozen(self);
|
889
|
+
if (0 < heap->size) {
|
890
|
+
heap->size = 0;
|
891
|
+
}
|
892
|
+
return self;
|
893
|
+
}
|
363
894
|
|
364
|
-
|
365
|
-
|
366
|
-
|
895
|
+
/********************************************************************
|
896
|
+
*
|
897
|
+
* DHeap setup
|
898
|
+
*
|
899
|
+
********************************************************************/
|
367
900
|
|
368
|
-
|
369
|
-
|
901
|
+
void
|
902
|
+
Init_d_heap(void)
|
903
|
+
{
|
904
|
+
VALUE rb_cDHeap = rb_define_class("DHeap", rb_cObject);
|
370
905
|
|
906
|
+
id_cmp = rb_intern_const("<=>");
|
907
|
+
id_abs = rb_intern_const("abs");
|
908
|
+
id_lshift = rb_intern_const("<<");
|
909
|
+
id_unary_minus = rb_intern_const("-@");
|
910
|
+
|
911
|
+
rb_define_alloc_func(rb_cDHeap, dheap_s_alloc);
|
912
|
+
|
913
|
+
/*
|
914
|
+
* This is based on INT_MAX. But it is very very unlikely you will want a
|
915
|
+
* large value for d. The tradeoff is that higher d values give faster push
|
916
|
+
* and slower pop. If you expect pushes and pops to be balanced, then just
|
917
|
+
* stick with the default. If you expect more pushes than pops, it might be
|
918
|
+
* worthwhile to increase d.
|
919
|
+
*/
|
920
|
+
rb_define_const(rb_cDHeap, "MAX_D", INT2NUM(DHEAP_MAX_D));
|
921
|
+
|
922
|
+
/*
|
923
|
+
* d=4 uses the fewest comparisons for (worst case) insert + delete-min.
|
924
|
+
*/
|
925
|
+
rb_define_const(rb_cDHeap, "DEFAULT_D", INT2NUM(DHEAP_DEFAULT_D));
|
926
|
+
|
927
|
+
/*
|
928
|
+
* The default heap capacity. The heap grows automatically as necessary, so
|
929
|
+
* you shouldn't need to worry about this.
|
930
|
+
*/
|
931
|
+
rb_define_const(rb_cDHeap, "DEFAULT_CAPA", INT2NUM(DHEAP_DEFAULT_CAPA));
|
932
|
+
|
933
|
+
rb_define_private_method(rb_cDHeap, "__init_without_kw__", dheap_initialize, 2);
|
934
|
+
rb_define_method(rb_cDHeap, "initialize_copy", dheap_initialize_copy, 1);
|
935
|
+
|
936
|
+
rb_define_method(rb_cDHeap, "d", dheap_attr_d, 0);
|
937
|
+
rb_define_method(rb_cDHeap, "size", dheap_size, 0);
|
938
|
+
rb_define_method(rb_cDHeap, "empty?", dheap_empty_p, 0);
|
371
939
|
rb_define_method(rb_cDHeap, "peek", dheap_peek, 0);
|
940
|
+
|
941
|
+
rb_define_method(rb_cDHeap, "clear", dheap_clear, 0);
|
942
|
+
rb_define_method(rb_cDHeap, "insert", dheap_insert, 2);
|
372
943
|
rb_define_method(rb_cDHeap, "push", dheap_push, -1);
|
373
944
|
rb_define_method(rb_cDHeap, "<<", dheap_left_shift, 1);
|
374
945
|
rb_define_method(rb_cDHeap, "pop", dheap_pop, 0);
|
375
|
-
|
376
|
-
rb_define_method(rb_cDHeap, "
|
946
|
+
|
947
|
+
rb_define_method(rb_cDHeap, "pop_lt", dheap_pop_lt, 1);
|
948
|
+
rb_define_method(rb_cDHeap, "pop_lte", dheap_pop_lte, 1);
|
949
|
+
rb_define_method(rb_cDHeap, "pop_all_below", dheap_pop_all_below, -1);
|
950
|
+
|
951
|
+
rb_define_method(rb_cDHeap, "peek_score", dheap_peek_score, 0);
|
952
|
+
rb_define_method(rb_cDHeap, "peek_with_score", dheap_peek_with_score, 0);
|
953
|
+
rb_define_method(rb_cDHeap, "pop_with_score", dheap_pop_with_score, 0);
|
954
|
+
|
377
955
|
}
|