d_heap 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +30 -1
- data/CHANGELOG.md +42 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +11 -10
- data/README.md +353 -121
- data/benchmarks/push_n.yml +28 -0
- data/benchmarks/push_n_pop_n.yml +31 -0
- data/benchmarks/push_pop.yml +24 -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 +2 -1
- data/docs/benchmarks-2.txt +52 -0
- data/docs/benchmarks.txt +443 -0
- data/docs/profile.txt +392 -0
- data/ext/d_heap/d_heap.c +428 -150
- data/ext/d_heap/d_heap.h +6 -3
- data/ext/d_heap/extconf.rb +8 -3
- data/lib/benchmark_driver/runner/ips_zero_fail.rb +120 -0
- data/lib/d_heap.rb +5 -3
- data/lib/d_heap/benchmarks.rb +111 -0
- data/lib/d_heap/benchmarks/benchmarker.rb +113 -0
- data/lib/d_heap/benchmarks/implementations.rb +168 -0
- data/lib/d_heap/benchmarks/profiler.rb +71 -0
- data/lib/d_heap/benchmarks/rspec_matchers.rb +374 -0
- data/lib/d_heap/version.rb +1 -1
- metadata +34 -3
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,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
|
5
|
-
ID id_ivar_scores;
|
6
|
-
ID id_ivar_d;
|
7
|
+
ID id_abs; // abs
|
7
8
|
|
8
|
-
#
|
9
|
+
#ifdef SCORE_AS_LONG_DOUBLE
|
10
|
+
#define SCORE long double
|
11
|
+
#else
|
12
|
+
#define SCORE VALUE
|
13
|
+
#endif
|
9
14
|
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
17
|
-
#define
|
18
|
-
|
19
|
-
|
20
|
-
#
|
21
|
-
|
22
|
-
|
23
|
-
#define
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
-
|
29
|
-
|
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 =
|
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*))
|
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->
|
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
|
-
|
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->
|
130
|
-
|
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
|
137
|
-
|
351
|
+
/* :nodoc: */
|
352
|
+
static VALUE
|
353
|
+
dheap_initialize_copy(VALUE copy, VALUE orig)
|
138
354
|
{
|
139
|
-
|
140
|
-
|
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
|
-
|
151
|
-
|
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
|
-
|
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
|
-
#
|
165
|
-
|
166
|
-
|
167
|
-
|
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
|
-
|
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
|
-
|
195
|
-
|
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
|
-
|
204
|
-
|
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
|
-
|
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
|
-
|
217
|
-
|
218
|
-
|
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
|
-
|
230
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
446
|
+
last_sibidx = child_idx0 + heap->d - 1;
|
242
447
|
if (last_index < last_sibidx) last_sibidx = last_index;
|
243
|
-
|
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
|
-
|
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
|
-
|
261
|
-
|
262
|
-
|
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
|
-
|
333
|
-
|
334
|
-
|
550
|
+
VALUE scr, val;
|
551
|
+
dheap_t *heap;
|
552
|
+
long last_index;
|
553
|
+
rb_check_frozen(self);
|
335
554
|
|
336
|
-
|
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
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
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
|
-
|
377
|
-
|
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
|
-
|
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 [
|
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
|
-
|
695
|
+
pop_value = DHEAP_VALUE(heap, 0);
|
427
696
|
|
428
|
-
|
429
|
-
|
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 [
|
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
|
-
|
722
|
+
pop_value = DHEAP_VALUE(heap, 0);
|
449
723
|
|
450
|
-
|
451
|
-
|
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
|
-
|
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, "
|
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, "
|
476
|
-
rb_define_method(rb_cDHeap, "
|
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);
|