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