d_heap 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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);
|