d_heap 0.6.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.clang-format +21 -0
- data/.github/workflows/main.yml +16 -1
- data/.rubocop.yml +1 -0
- data/CHANGELOG.md +17 -0
- data/{N → D} +1 -1
- data/README.md +313 -261
- data/d_heap.gemspec +16 -5
- data/docs/benchmarks-2.txt +79 -61
- data/docs/benchmarks.txt +587 -416
- data/docs/profile.txt +99 -133
- data/ext/d_heap/.rubocop.yml +7 -0
- data/ext/d_heap/d_heap.c +575 -424
- data/ext/d_heap/extconf.rb +34 -3
- data/images/push_n.png +0 -0
- data/images/push_n_pop_n.png +0 -0
- data/images/push_pop.png +0 -0
- data/lib/d_heap.rb +25 -1
- data/lib/d_heap/version.rb +1 -1
- metadata +6 -30
- data/.rspec +0 -3
- data/.travis.yml +0 -6
- data/Gemfile +0 -20
- data/Gemfile.lock +0 -83
- data/Rakefile +0 -20
- data/benchmarks/perf.rb +0 -29
- data/benchmarks/push_n.yml +0 -35
- data/benchmarks/push_n_pop_n.yml +0 -52
- data/benchmarks/push_pop.yml +0 -32
- data/benchmarks/stackprof.rb +0 -31
- data/bin/bench_charts +0 -13
- data/bin/bench_n +0 -7
- data/bin/benchmark-driver +0 -29
- data/bin/benchmarks +0 -10
- data/bin/console +0 -15
- data/bin/profile +0 -10
- data/bin/rake +0 -29
- data/bin/rspec +0 -29
- data/bin/rubocop +0 -29
- data/bin/setup +0 -8
- data/lib/benchmark_driver/runner/ips_zero_fail.rb +0 -158
- data/lib/d_heap/benchmarks.rb +0 -112
- data/lib/d_heap/benchmarks/benchmarker.rb +0 -116
- data/lib/d_heap/benchmarks/implementations.rb +0 -224
- data/lib/d_heap/benchmarks/profiler.rb +0 -71
- data/lib/d_heap/benchmarks/rspec_matchers.rb +0 -352
data/docs/profile.txt
CHANGED
@@ -1,29 +1,28 @@
|
|
1
|
-
Profiling run at 2021-01
|
2
|
-
ruby v2.7.2, DHeap v0.
|
1
|
+
Profiling run at 2021-02-01 00:43:34 -0500
|
2
|
+
ruby v2.7.2, DHeap v0.6.1
|
3
3
|
|
4
4
|
~~~~~~ filling @dheap_bm_random_vals with 1.0M ~~~~~~
|
5
5
|
########################################################################
|
6
|
-
# Profile w/ N=
|
6
|
+
# Profile w/ N=10 (i=1000000)
|
7
7
|
# (n.b. RubyProf & tracepoint can change relative performance.
|
8
8
|
# A sampling profiler can provide more accurate relative metrics.
|
9
9
|
########################################################################
|
10
10
|
|
11
|
-
Filling
|
12
|
-
Profiling
|
11
|
+
Filling ruby binary heap ---------------------------
|
12
|
+
Profiling ruby binary heap ---------------------------
|
13
13
|
Measure Mode: wall_time
|
14
|
-
Thread ID:
|
15
|
-
Fiber ID:
|
16
|
-
Total:
|
14
|
+
Thread ID: 1400
|
15
|
+
Fiber ID: 1380
|
16
|
+
Total: 5.194751
|
17
17
|
Sort by: self_time
|
18
18
|
|
19
19
|
%self total self wait child calls name location
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
4.81 0.127 0.127 0.000 0.000 1000000 Array#fetch
|
20
|
+
41.50 2.156 2.156 0.000 0.000 1000000 DHeap::Benchmarks::RbHeap#<< /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:107
|
21
|
+
36.37 2.137 1.889 0.000 0.247 1000000 DHeap::Benchmarks::RbHeap#pop /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:121
|
22
|
+
14.92 5.195 0.775 0.000 4.420 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
|
23
|
+
2.46 0.128 0.128 0.000 0.000 1000000 Array#fetch
|
24
|
+
2.41 0.125 0.125 0.000 0.000 1000000 Array#pop
|
25
|
+
2.35 0.122 0.122 0.000 0.000 1000000 Array#first
|
27
26
|
|
28
27
|
* recursively called methods
|
29
28
|
|
@@ -43,22 +42,19 @@ The interpretation of method names is:
|
|
43
42
|
* MyObject#test - An instance method "test" of the class "MyObject"
|
44
43
|
* <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
|
45
44
|
|
46
|
-
Filling
|
47
|
-
Profiling
|
45
|
+
Filling quaternary DHeap ---------------------------
|
46
|
+
Profiling quaternary DHeap ---------------------------
|
48
47
|
Measure Mode: wall_time
|
49
|
-
Thread ID:
|
50
|
-
Fiber ID:
|
51
|
-
Total:
|
48
|
+
Thread ID: 1400
|
49
|
+
Fiber ID: 1380
|
50
|
+
Total: 1.103473
|
52
51
|
Sort by: self_time
|
53
52
|
|
54
53
|
%self total self wait child calls name location
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
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
|
54
|
+
64.92 1.103 0.716 0.000 0.387 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
|
55
|
+
12.09 0.133 0.133 0.000 0.000 1000000 DHeap#<<
|
56
|
+
11.82 0.130 0.130 0.000 0.000 1000000 DHeap#pop
|
57
|
+
11.16 0.123 0.123 0.000 0.000 1000000 Array#fetch
|
62
58
|
|
63
59
|
* recursively called methods
|
64
60
|
|
@@ -78,23 +74,27 @@ The interpretation of method names is:
|
|
78
74
|
* MyObject#test - An instance method "test" of the class "MyObject"
|
79
75
|
* <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
|
80
76
|
|
77
|
+
########################################################################
|
78
|
+
# Profile w/ N=100 (i=1000000)
|
79
|
+
# (n.b. RubyProf & tracepoint can change relative performance.
|
80
|
+
# A sampling profiler can provide more accurate relative metrics.
|
81
|
+
########################################################################
|
82
|
+
|
81
83
|
Filling ruby binary heap ---------------------------
|
82
84
|
Profiling ruby binary heap ---------------------------
|
83
85
|
Measure Mode: wall_time
|
84
|
-
Thread ID:
|
85
|
-
Fiber ID:
|
86
|
-
Total:
|
86
|
+
Thread ID: 1400
|
87
|
+
Fiber ID: 1380
|
88
|
+
Total: 7.422039
|
87
89
|
Sort by: self_time
|
88
90
|
|
89
91
|
%self total self wait child calls name location
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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
|
92
|
+
47.72 3.542 3.542 0.000 0.000 1000000 DHeap::Benchmarks::RbHeap#<< /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:107
|
93
|
+
36.82 2.984 2.733 0.000 0.251 1000000 DHeap::Benchmarks::RbHeap#pop /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:121
|
94
|
+
10.39 7.422 0.771 0.000 6.651 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
|
95
|
+
1.71 0.127 0.127 0.000 0.000 1000000 Array#pop
|
96
|
+
1.69 0.125 0.125 0.000 0.000 1000000 Array#fetch
|
97
|
+
1.67 0.124 0.124 0.000 0.000 1000000 Array#first
|
98
98
|
|
99
99
|
* recursively called methods
|
100
100
|
|
@@ -117,16 +117,16 @@ The interpretation of method names is:
|
|
117
117
|
Filling quaternary DHeap ---------------------------
|
118
118
|
Profiling quaternary DHeap ---------------------------
|
119
119
|
Measure Mode: wall_time
|
120
|
-
Thread ID:
|
121
|
-
Fiber ID:
|
122
|
-
Total: 1.
|
120
|
+
Thread ID: 1400
|
121
|
+
Fiber ID: 1380
|
122
|
+
Total: 1.163539
|
123
123
|
Sort by: self_time
|
124
124
|
|
125
125
|
%self total self wait child calls name location
|
126
|
-
|
127
|
-
|
128
|
-
12.
|
129
|
-
10.
|
126
|
+
64.38 1.164 0.749 0.000 0.414 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
|
127
|
+
12.52 0.146 0.146 0.000 0.000 1000000 DHeap#<<
|
128
|
+
12.43 0.145 0.145 0.000 0.000 1000000 DHeap#pop
|
129
|
+
10.67 0.124 0.124 0.000 0.000 1000000 Array#fetch
|
130
130
|
|
131
131
|
* recursively called methods
|
132
132
|
|
@@ -147,23 +147,26 @@ The interpretation of method names is:
|
|
147
147
|
* <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
|
148
148
|
|
149
149
|
########################################################################
|
150
|
-
# Profile w/ N=
|
150
|
+
# Profile w/ N=1000 (i=1000000)
|
151
151
|
# (n.b. RubyProf & tracepoint can change relative performance.
|
152
152
|
# A sampling profiler can provide more accurate relative metrics.
|
153
153
|
########################################################################
|
154
154
|
|
155
|
-
Filling
|
156
|
-
Profiling
|
155
|
+
Filling ruby binary heap ---------------------------
|
156
|
+
Profiling ruby binary heap ---------------------------
|
157
157
|
Measure Mode: wall_time
|
158
|
-
Thread ID:
|
159
|
-
Fiber ID:
|
160
|
-
Total:
|
158
|
+
Thread ID: 1400
|
159
|
+
Fiber ID: 1380
|
160
|
+
Total: 9.693127
|
161
161
|
Sort by: self_time
|
162
162
|
|
163
163
|
%self total self wait child calls name location
|
164
|
-
|
165
|
-
|
166
|
-
|
164
|
+
52.28 5.068 5.068 0.000 0.000 1000000 DHeap::Benchmarks::RbHeap#<< /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:107
|
165
|
+
35.52 3.702 3.443 0.000 0.259 1000000 DHeap::Benchmarks::RbHeap#pop /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:121
|
166
|
+
8.18 9.693 0.793 0.000 8.900 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
|
167
|
+
1.36 0.131 0.131 0.000 0.000 1000000 Array#pop
|
168
|
+
1.35 0.131 0.131 0.000 0.000 1000000 Array#fetch
|
169
|
+
1.32 0.128 0.128 0.000 0.000 1000000 Array#first
|
167
170
|
|
168
171
|
* recursively called methods
|
169
172
|
|
@@ -183,22 +186,19 @@ The interpretation of method names is:
|
|
183
186
|
* MyObject#test - An instance method "test" of the class "MyObject"
|
184
187
|
* <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
|
185
188
|
|
186
|
-
Filling
|
187
|
-
Profiling
|
189
|
+
Filling quaternary DHeap ---------------------------
|
190
|
+
Profiling quaternary DHeap ---------------------------
|
188
191
|
Measure Mode: wall_time
|
189
|
-
Thread ID:
|
190
|
-
Fiber ID:
|
191
|
-
Total:
|
192
|
+
Thread ID: 1400
|
193
|
+
Fiber ID: 1380
|
194
|
+
Total: 1.125575
|
192
195
|
Sort by: self_time
|
193
196
|
|
194
197
|
%self total self wait child calls name location
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
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
|
198
|
+
64.22 1.126 0.723 0.000 0.403 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
|
199
|
+
13.16 0.148 0.148 0.000 0.000 1000000 DHeap#<<
|
200
|
+
12.01 0.135 0.135 0.000 0.000 1000000 DHeap#pop
|
201
|
+
10.62 0.119 0.119 0.000 0.000 1000000 Array#fetch
|
202
202
|
|
203
203
|
* recursively called methods
|
204
204
|
|
@@ -218,23 +218,24 @@ The interpretation of method names is:
|
|
218
218
|
* MyObject#test - An instance method "test" of the class "MyObject"
|
219
219
|
* <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
|
220
220
|
|
221
|
+
########################################################################
|
222
|
+
# Profile w/ N=10000 (i=1000000)
|
223
|
+
# (n.b. RubyProf & tracepoint can change relative performance.
|
224
|
+
# A sampling profiler can provide more accurate relative metrics.
|
225
|
+
########################################################################
|
226
|
+
|
221
227
|
Filling ruby binary heap ---------------------------
|
222
228
|
Profiling ruby binary heap ---------------------------
|
223
229
|
Measure Mode: wall_time
|
224
|
-
Thread ID:
|
225
|
-
Fiber ID:
|
226
|
-
Total:
|
230
|
+
Thread ID: 1400
|
231
|
+
Fiber ID: 1380
|
232
|
+
Total: 13.737007
|
227
233
|
Sort by: self_time
|
228
234
|
|
229
235
|
%self total self wait child calls name location
|
230
|
-
|
231
|
-
|
232
|
-
|
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
|
236
|
+
49.46 6.794 6.794 0.000 0.000 1000000 DHeap::Benchmarks::RbHeap#<< /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:107
|
237
|
+
41.97 6.017 5.765 0.000 0.251 1000000 DHeap::Benchmarks::RbHeap#pop /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:121
|
238
|
+
5.80 13.737 0.796 0.000 12.941 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
|
238
239
|
|
239
240
|
* recursively called methods
|
240
241
|
|
@@ -257,16 +258,16 @@ The interpretation of method names is:
|
|
257
258
|
Filling quaternary DHeap ---------------------------
|
258
259
|
Profiling quaternary DHeap ---------------------------
|
259
260
|
Measure Mode: wall_time
|
260
|
-
Thread ID:
|
261
|
-
Fiber ID:
|
262
|
-
Total: 1.
|
261
|
+
Thread ID: 1400
|
262
|
+
Fiber ID: 1380
|
263
|
+
Total: 1.179968
|
263
264
|
Sort by: self_time
|
264
265
|
|
265
266
|
%self total self wait child calls name location
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
267
|
+
62.48 1.180 0.737 0.000 0.443 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
|
268
|
+
13.86 0.164 0.164 0.000 0.000 1000000 DHeap#<<
|
269
|
+
13.46 0.159 0.159 0.000 0.000 1000000 DHeap#pop
|
270
|
+
10.20 0.120 0.120 0.000 0.000 1000000 Array#fetch
|
270
271
|
|
271
272
|
* recursively called methods
|
272
273
|
|
@@ -287,58 +288,23 @@ The interpretation of method names is:
|
|
287
288
|
* <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
|
288
289
|
|
289
290
|
########################################################################
|
290
|
-
# Profile w/ N=
|
291
|
+
# Profile w/ N=100000 (i=1000000)
|
291
292
|
# (n.b. RubyProf & tracepoint can change relative performance.
|
292
293
|
# A sampling profiler can provide more accurate relative metrics.
|
293
294
|
########################################################################
|
294
295
|
|
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
296
|
Filling ruby binary heap ---------------------------
|
331
297
|
Profiling ruby binary heap ---------------------------
|
332
298
|
Measure Mode: wall_time
|
333
|
-
Thread ID:
|
334
|
-
Fiber ID:
|
335
|
-
Total: 16.
|
299
|
+
Thread ID: 1400
|
300
|
+
Fiber ID: 1380
|
301
|
+
Total: 16.425915
|
336
302
|
Sort by: self_time
|
337
303
|
|
338
304
|
%self total self wait child calls name location
|
339
|
-
|
340
|
-
|
341
|
-
|
305
|
+
50.99 8.623 8.376 0.000 0.247 1000000 DHeap::Benchmarks::RbHeap#pop /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:121
|
306
|
+
41.82 6.869 6.869 0.000 0.000 1000000 DHeap::Benchmarks::RbHeap#<< /home/nick/src/d_heap/lib/d_heap/benchmarks/implementations.rb:107
|
307
|
+
4.89 16.426 0.803 0.000 15.623 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
|
342
308
|
|
343
309
|
* recursively called methods
|
344
310
|
|
@@ -361,16 +327,16 @@ The interpretation of method names is:
|
|
361
327
|
Filling quaternary DHeap ---------------------------
|
362
328
|
Profiling quaternary DHeap ---------------------------
|
363
329
|
Measure Mode: wall_time
|
364
|
-
Thread ID:
|
365
|
-
Fiber ID:
|
366
|
-
Total: 1.
|
330
|
+
Thread ID: 1400
|
331
|
+
Fiber ID: 1380
|
332
|
+
Total: 1.205573
|
367
333
|
Sort by: self_time
|
368
334
|
|
369
335
|
%self total self wait child calls name location
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
336
|
+
59.14 1.206 0.713 0.000 0.493 1 DHeap::Benchmarks::Scenarios#repeated_push_pop /home/nick/src/d_heap/lib/d_heap/benchmarks.rb:81
|
337
|
+
16.93 0.204 0.204 0.000 0.000 1000000 DHeap#pop
|
338
|
+
13.88 0.167 0.167 0.000 0.000 1000000 DHeap#<<
|
339
|
+
10.05 0.121 0.121 0.000 0.000 1000000 Array#fetch
|
374
340
|
|
375
341
|
* recursively called methods
|
376
342
|
|
data/ext/d_heap/d_heap.c
CHANGED
@@ -1,165 +1,126 @@
|
|
1
|
+
#include "ruby.h"
|
1
2
|
#include <float.h>
|
2
3
|
#include <math.h>
|
3
|
-
#include "ruby.h"
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
*
|
9
|
-
********************************************************************/
|
10
|
-
|
11
|
-
typedef struct dheap_struct dheap_t;
|
12
|
-
typedef struct dheap_entry ENTRY;
|
5
|
+
#if CHAR_BIT != 8
|
6
|
+
# error "DHeap assumes 8-bit bytes"
|
7
|
+
#endif
|
13
8
|
|
14
|
-
|
15
|
-
|
9
|
+
#if SIZE_MAX != ULONG_MAX
|
10
|
+
# error "DHeap assumes 'size_t' is 'unsigned long'"
|
11
|
+
#endif
|
16
12
|
|
17
13
|
#if LDBL_MANT_DIG < SIZEOF_UNSIGNED_LONG_LONG * 8
|
18
|
-
#error '
|
14
|
+
# error "DHeap assumes 'long double' mantissa can store 'unsigned long long'"
|
19
15
|
#endif
|
20
16
|
|
21
17
|
// TODO: test this code on a 32 bit system (it MUST have some bugs!)
|
18
|
+
// TODO: perhaps just convert from "unsigned long long" to "uint64_t"!
|
22
19
|
#if SIZEOF_UNSIGNED_LONG_LONG * 8 != 64
|
23
|
-
#error 'unsigned long long'
|
20
|
+
# error "DHeap assumes 64-bit 'unsigned long long'"
|
24
21
|
#endif
|
25
22
|
|
23
|
+
/********************************************************************
|
24
|
+
*
|
25
|
+
* Type definitions
|
26
|
+
*
|
27
|
+
********************************************************************/
|
28
|
+
|
29
|
+
typedef struct dheap_struct dheap_t;
|
30
|
+
typedef struct dheap_entry ENTRY;
|
31
|
+
|
32
|
+
typedef double SCORE;
|
33
|
+
|
26
34
|
/********************************************************************
|
27
35
|
*
|
28
36
|
* Struct definitions
|
29
37
|
*
|
30
38
|
********************************************************************/
|
31
39
|
|
32
|
-
struct dheap_struct
|
33
|
-
|
34
|
-
|
35
|
-
|
40
|
+
struct dheap_struct
|
41
|
+
{
|
42
|
+
int d;
|
43
|
+
size_t size;
|
44
|
+
size_t capa;
|
36
45
|
ENTRY *entries;
|
46
|
+
#ifdef DHEAP_MAP
|
47
|
+
VALUE indexes; // Hash
|
48
|
+
#endif
|
37
49
|
};
|
38
50
|
|
39
|
-
struct dheap_entry
|
51
|
+
struct dheap_entry
|
52
|
+
{
|
40
53
|
SCORE score;
|
41
54
|
VALUE value;
|
42
55
|
};
|
43
56
|
|
57
|
+
#define DHEAPMAP_P(heap) UNLIKELY(RTEST((heap)->indexes))
|
58
|
+
|
44
59
|
/********************************************************************
|
45
60
|
*
|
46
61
|
* Constant definitions
|
47
62
|
*
|
48
63
|
********************************************************************/
|
49
64
|
|
50
|
-
#define DHEAP_DEFAULT_D
|
51
|
-
#define DHEAP_MAX_D
|
65
|
+
#define DHEAP_DEFAULT_D 6
|
66
|
+
#define DHEAP_MAX_D INT_MAX
|
52
67
|
|
53
|
-
// sizeof(ENTRY) =>
|
68
|
+
// sizeof(ENTRY) => 16 bytes, 128-bits
|
54
69
|
// one kilobyte = 32 * 32 bytes
|
55
|
-
#define DHEAP_DEFAULT_CAPA
|
56
|
-
#define DHEAP_MAX_CAPA
|
70
|
+
#define DHEAP_DEFAULT_CAPA 32
|
71
|
+
#define DHEAP_MAX_CAPA (SIZE_MAX / (int)sizeof(ENTRY))
|
57
72
|
#define DHEAP_CAPA_INCR_MAX (10 * 1024 * 1024 / (int)sizeof(ENTRY))
|
58
73
|
|
59
|
-
static ID id_cmp;
|
60
|
-
static ID id_abs;
|
74
|
+
static ID id_cmp; // <=>
|
75
|
+
static ID id_abs; // abs
|
61
76
|
static ID id_lshift; // <<
|
62
|
-
static ID
|
63
|
-
|
77
|
+
static ID id_uminus; // -@
|
78
|
+
|
64
79
|
static const rb_data_type_t dheap_data_type;
|
65
80
|
|
66
81
|
/********************************************************************
|
67
82
|
*
|
68
|
-
*
|
69
|
-
* adapted from similar methods in ruby's object.c
|
83
|
+
* Metaprogramming macros
|
70
84
|
*
|
71
85
|
********************************************************************/
|
72
86
|
|
73
|
-
|
74
|
-
|
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
|
-
}
|
87
|
+
#define LIKELY RB_LIKELY
|
88
|
+
#define UNLIKELY RB_UNLIKELY
|
112
89
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
90
|
+
#ifdef DHEAP_MAP
|
91
|
+
# define DHEAP_DISPATCH_EXPR(func, heap, ...) \
|
92
|
+
(DHEAPMAP_P(heap) ? dheapmap_##func(heap, __VA_ARGS__) \
|
93
|
+
: dheap_##func(heap, __VA_ARGS__))
|
94
|
+
#else
|
95
|
+
# define DHEAP_DISPATCH_EXPR(func, heap, ...) \
|
96
|
+
dheap_##func(heap, __VA_ARGS__);
|
97
|
+
#endif
|
118
98
|
|
119
|
-
|
120
|
-
|
121
|
-
{
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
99
|
+
#ifdef DHEAP_MAP
|
100
|
+
# define DHEAP_DISPATCH_STMT(heap, macro, ...) \
|
101
|
+
do { \
|
102
|
+
if (DHEAPMAP_P(heap)) { \
|
103
|
+
macro(dheapmap, heap, __VA_ARGS__); \
|
104
|
+
} else { \
|
105
|
+
macro(dheap, heap, __VA_ARGS__); \
|
106
|
+
} \
|
107
|
+
} while (0)
|
108
|
+
#else
|
109
|
+
# define DHEAP_DISPATCH_STMT(heap, macro, ...) \
|
110
|
+
macro(dheap, heap, __VA_ARGS__)
|
111
|
+
#endif
|
126
112
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
}
|
113
|
+
/********************************************************************
|
114
|
+
*
|
115
|
+
* SCORE: casting to and from VALUE
|
116
|
+
* adapted from similar methods in ruby's object.c
|
117
|
+
*
|
118
|
+
********************************************************************/
|
134
119
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
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
|
-
}
|
120
|
+
#define SCORE2NUM(score) rb_float_new(score)
|
121
|
+
#define VAL2SCORE(val) NUM2DBL(RB_FLOAT_TYPE_P(val) ? val : rb_Float(val))
|
122
|
+
#define CMP_LT(a, b) ((a) < (b))
|
123
|
+
#define CMP_LTE(a, b) ((a) <= (b))
|
163
124
|
|
164
125
|
/********************************************************************
|
165
126
|
*
|
@@ -167,17 +128,28 @@ VAL2SCORE(VALUE score)
|
|
167
128
|
*
|
168
129
|
********************************************************************/
|
169
130
|
|
170
|
-
#define DHEAP_SCORE(heap, idx) ((heap)
|
171
|
-
#define DHEAP_VALUE(heap, idx) ((heap)
|
131
|
+
#define DHEAP_SCORE(heap, idx) (DHEAP_GET(heap, idx).score)
|
132
|
+
#define DHEAP_VALUE(heap, idx) (DHEAP_GET(heap, idx).value)
|
172
133
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
134
|
+
#define DHEAP_ENTRY_ARY(heap, idx) \
|
135
|
+
(((heap)->size <= (idx)) \
|
136
|
+
? Qnil \
|
137
|
+
: rb_ary_new_from_args( \
|
138
|
+
2, DHEAP_VALUE(heap, idx), SCORE2NUM(DHEAP_SCORE(heap, idx))))
|
139
|
+
|
140
|
+
#define DHEAP_GET(heap, idx) ((heap)->entries[idx])
|
141
|
+
#define DHEAP_SET(T, heap, index, entry) \
|
142
|
+
do { \
|
143
|
+
DHEAP_GET(heap, index) = (entry); \
|
144
|
+
DHEAP_SET_##T(heap, index, entry); \
|
145
|
+
} while (0)
|
146
|
+
|
147
|
+
#define DHEAP_SET_dheap(heap, index, entry) /* noop */
|
148
|
+
|
149
|
+
#ifdef DHEAP_MAP
|
150
|
+
# define DHEAP_SET_dheapmap(heap, index, entry) \
|
151
|
+
rb_hash_aset((heap)->indexes, (entry).value, ULONG2NUM(index))
|
152
|
+
#endif
|
181
153
|
|
182
154
|
/********************************************************************
|
183
155
|
*
|
@@ -185,22 +157,20 @@ DHEAP_ENTRY_ARY(dheap_t *heap, long idx)
|
|
185
157
|
*
|
186
158
|
********************************************************************/
|
187
159
|
|
188
|
-
#define DHEAP_IDX_LAST(heap)
|
189
|
-
#define DHEAP_IDX_PARENT(heap, idx)
|
160
|
+
#define DHEAP_IDX_LAST(heap) ((heap)->size - 1)
|
161
|
+
#define DHEAP_IDX_PARENT(heap, idx) (((idx)-1) / (heap)->d)
|
190
162
|
#define DHEAP_IDX_CHILD_0(heap, idx) (((idx) * (heap)->d) + 1)
|
191
163
|
#define DHEAP_IDX_CHILD_D(heap, idx) (((idx) * (heap)->d) + (heap)->d)
|
192
164
|
|
193
|
-
#ifdef
|
194
|
-
#define ASSERT_DHEAP_IDX_OK(heap, index)
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
} \
|
201
|
-
} while (0)
|
165
|
+
#ifdef DEBUG
|
166
|
+
# define ASSERT_DHEAP_IDX_OK(heap, index) \
|
167
|
+
do { \
|
168
|
+
if (DHEAP_IDX_LAST(heap) < index) { \
|
169
|
+
rb_raise(rb_eIndexError, "DHeap index %ld too large", index); \
|
170
|
+
} \
|
171
|
+
} while (0)
|
202
172
|
#else
|
203
|
-
#define ASSERT_DHEAP_IDX_OK(heap, index)
|
173
|
+
# define ASSERT_DHEAP_IDX_OK(heap, index)
|
204
174
|
#endif
|
205
175
|
|
206
176
|
/********************************************************************
|
@@ -214,113 +184,79 @@ static void
|
|
214
184
|
dheap_compact(void *ptr)
|
215
185
|
{
|
216
186
|
dheap_t *heap = ptr;
|
217
|
-
for (
|
187
|
+
for (size_t i = 0; i < heap->size; ++i) {
|
218
188
|
if (DHEAP_VALUE(heap, i))
|
219
|
-
rb_gc_location(DHEAP_VALUE(heap, i));
|
189
|
+
DHEAP_VALUE(heap, i) = rb_gc_location(DHEAP_VALUE(heap, i));
|
220
190
|
}
|
191
|
+
# ifdef DHEAP_MAP
|
192
|
+
if (DHEAPMAP_P(heap)) heap->indexes = rb_gc_location(heap->indexes);
|
193
|
+
# endif
|
221
194
|
}
|
222
195
|
#else
|
223
|
-
#define rb_gc_mark_movable(x) rb_gc_mark(x)
|
196
|
+
# define rb_gc_mark_movable(x) rb_gc_mark(x)
|
224
197
|
#endif
|
225
198
|
|
226
199
|
static void
|
227
200
|
dheap_mark(void *ptr)
|
228
201
|
{
|
229
202
|
dheap_t *heap = ptr;
|
230
|
-
for (
|
231
|
-
if (DHEAP_VALUE(heap, i))
|
232
|
-
rb_gc_mark_movable(DHEAP_VALUE(heap,i));
|
203
|
+
for (size_t i = 0; i < heap->size; ++i) {
|
204
|
+
if (DHEAP_VALUE(heap, i)) rb_gc_mark_movable(DHEAP_VALUE(heap, i));
|
233
205
|
}
|
206
|
+
#ifdef DHEAP_MAP
|
207
|
+
if (DHEAPMAP_P(heap)) rb_gc_mark_movable(heap->indexes);
|
208
|
+
#endif
|
234
209
|
}
|
235
210
|
|
236
211
|
static void
|
237
212
|
dheap_free(void *ptr)
|
238
213
|
{
|
239
214
|
dheap_t *heap = ptr;
|
240
|
-
heap->size
|
215
|
+
heap->size = 0;
|
241
216
|
if (heap->entries) {
|
242
217
|
xfree(heap->entries);
|
243
218
|
heap->entries = NULL;
|
244
219
|
}
|
245
220
|
heap->capa = 0;
|
246
221
|
xfree(ptr);
|
222
|
+
#ifdef DHEAP_MAP
|
223
|
+
heap->indexes = Qnil;
|
224
|
+
#endif
|
247
225
|
}
|
248
226
|
|
249
227
|
static size_t
|
250
228
|
dheap_memsize(const void *ptr)
|
251
229
|
{
|
252
230
|
const dheap_t *heap = ptr;
|
253
|
-
size_t
|
231
|
+
size_t size = 0;
|
254
232
|
size += sizeof(*heap);
|
255
233
|
size += sizeof(ENTRY) * heap->capa;
|
256
234
|
return size;
|
257
235
|
}
|
258
236
|
|
259
|
-
|
260
237
|
static const rb_data_type_t dheap_data_type = {
|
261
238
|
"DHeap",
|
262
|
-
{
|
263
|
-
|
264
|
-
|
265
|
-
(size_t (*)(const void *))dheap_memsize,
|
239
|
+
{ (void (*)(void *))dheap_mark,
|
240
|
+
(void (*)(void *))dheap_free,
|
241
|
+
(size_t(*)(const void *))dheap_memsize,
|
266
242
|
#ifdef HAVE_RB_GC_MARK_MOVABLE
|
267
|
-
|
243
|
+
(void (*)(void *))dheap_compact,
|
244
|
+
{ 0 }
|
268
245
|
#else
|
269
|
-
|
246
|
+
{ 0 }
|
270
247
|
#endif
|
271
248
|
},
|
272
|
-
0,
|
249
|
+
0,
|
250
|
+
0,
|
273
251
|
RUBY_TYPED_FREE_IMMEDIATELY,
|
274
252
|
};
|
275
253
|
|
276
254
|
/********************************************************************
|
277
255
|
*
|
278
256
|
* DHeap comparisons
|
279
|
-
* TODO: bring back comparisons for score types other than `long double`.
|
280
257
|
*
|
281
258
|
********************************************************************/
|
282
259
|
|
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
260
|
/********************************************************************
|
325
261
|
*
|
326
262
|
* DHeap allocation and initialization and resizing
|
@@ -330,19 +266,21 @@ static const rb_data_type_t dheap_data_type = {
|
|
330
266
|
static VALUE
|
331
267
|
dheap_s_alloc(VALUE klass)
|
332
268
|
{
|
333
|
-
VALUE
|
269
|
+
VALUE obj;
|
334
270
|
dheap_t *heap;
|
335
271
|
|
336
|
-
// TypedData_Make_Struct uses a non-std "statement expression"
|
337
272
|
#pragma GCC diagnostic push
|
338
273
|
#pragma GCC diagnostic ignored "-Wpedantic"
|
274
|
+
// TypedData_Make_Struct uses a non-std "statement expression"
|
339
275
|
obj = TypedData_Make_Struct(klass, dheap_t, &dheap_data_type, heap);
|
340
276
|
#pragma GCC diagnostic pop
|
341
|
-
heap->d
|
342
|
-
|
343
|
-
heap->
|
344
|
-
heap->capa = 0;
|
277
|
+
heap->d = DHEAP_DEFAULT_D;
|
278
|
+
heap->size = 0;
|
279
|
+
heap->capa = 0;
|
345
280
|
heap->entries = NULL;
|
281
|
+
#ifdef DHEAP_MAP
|
282
|
+
heap->indexes = Qnil;
|
283
|
+
#endif
|
346
284
|
|
347
285
|
return obj;
|
348
286
|
}
|
@@ -355,8 +293,15 @@ get_dheap_struct(VALUE self)
|
|
355
293
|
return heap;
|
356
294
|
}
|
357
295
|
|
296
|
+
static inline dheap_t *
|
297
|
+
get_dheap_struct_unfrozen(VALUE self)
|
298
|
+
{
|
299
|
+
rb_check_frozen(self);
|
300
|
+
return get_dheap_struct(self);
|
301
|
+
}
|
302
|
+
|
358
303
|
void
|
359
|
-
dheap_set_capa(dheap_t *heap,
|
304
|
+
dheap_set_capa(dheap_t *heap, size_t new_capa)
|
360
305
|
{
|
361
306
|
// Do nothing if we already have the capacity or are resizing too small
|
362
307
|
if (new_capa <= heap->capa || new_capa <= heap->size) return;
|
@@ -371,27 +316,36 @@ dheap_set_capa(dheap_t *heap, long new_capa)
|
|
371
316
|
}
|
372
317
|
|
373
318
|
static void
|
374
|
-
|
319
|
+
dheap_incr_capa(dheap_t *heap, size_t new_size)
|
375
320
|
{
|
376
|
-
|
321
|
+
size_t new_capa = heap->capa;
|
322
|
+
while (new_capa < new_size) {
|
323
|
+
if (new_capa <= DHEAP_CAPA_INCR_MAX) {
|
324
|
+
// double it... up to DHEAP_CAPA_INCR_MAX
|
325
|
+
new_capa *= 2;
|
326
|
+
} else if (DHEAP_MAX_CAPA - DHEAP_CAPA_INCR_MAX < heap->capa) {
|
327
|
+
// avoid overflow
|
328
|
+
new_capa = DHEAP_MAX_CAPA;
|
329
|
+
} else {
|
330
|
+
new_capa += DHEAP_CAPA_INCR_MAX;
|
331
|
+
}
|
332
|
+
}
|
333
|
+
dheap_set_capa(heap, new_capa);
|
334
|
+
}
|
377
335
|
|
336
|
+
static void
|
337
|
+
dheap_ensure_room_for_push(dheap_t *heap, size_t incr_by)
|
338
|
+
{
|
378
339
|
// check for overflow of new_size
|
379
|
-
if (DHEAP_MAX_CAPA - incr_by < heap->size)
|
380
|
-
rb_raise(rb_eIndexError,
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
if
|
387
|
-
|
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);
|
340
|
+
if (DHEAP_MAX_CAPA - incr_by < heap->size) {
|
341
|
+
rb_raise(rb_eIndexError,
|
342
|
+
"size increase overflow: %zu + %zu",
|
343
|
+
heap->size,
|
344
|
+
incr_by);
|
345
|
+
} else {
|
346
|
+
size_t new_size = heap->size + incr_by;
|
347
|
+
// if existing capacity is too small
|
348
|
+
if (heap->capa < new_size) dheap_incr_capa(heap, new_size);
|
395
349
|
}
|
396
350
|
}
|
397
351
|
|
@@ -399,34 +353,34 @@ static inline int
|
|
399
353
|
dheap_value_to_int_d(VALUE num)
|
400
354
|
{
|
401
355
|
int d = NUM2INT(num);
|
402
|
-
if (d < 2)
|
403
|
-
|
404
|
-
}
|
405
|
-
if (d > DHEAP_MAX_D) {
|
406
|
-
rb_raise(rb_eArgError, "DHeap d=%u is too large", d);
|
407
|
-
}
|
356
|
+
if (d < 2) rb_raise(rb_eArgError, "DHeap d=%u is too small", d);
|
357
|
+
if (d > DHEAP_MAX_D) rb_raise(rb_eArgError, "DHeap d=%u is too large", d);
|
408
358
|
return d;
|
409
359
|
}
|
410
360
|
|
411
|
-
static inline
|
412
|
-
|
361
|
+
static inline size_t
|
362
|
+
dheap_value_to_capa(VALUE num)
|
413
363
|
{
|
414
|
-
|
364
|
+
size_t capa = NUM2ULONG(num);
|
415
365
|
if (capa < 1) {
|
416
|
-
rb_raise(rb_eArgError, "DHeap capa=%
|
366
|
+
rb_raise(rb_eArgError, "DHeap capa=%zu must be positive", capa);
|
417
367
|
}
|
418
368
|
return capa;
|
419
369
|
}
|
420
370
|
|
421
371
|
static VALUE
|
422
|
-
|
372
|
+
dheap_init(VALUE self, VALUE d, VALUE capa, VALUE map)
|
373
|
+
{
|
423
374
|
dheap_t *heap = get_dheap_struct(self);
|
424
375
|
|
425
|
-
if(heap->entries || heap->size || heap->capa)
|
376
|
+
if (heap->entries || heap->size || heap->capa)
|
426
377
|
rb_raise(rb_eScriptError, "DHeap already initialized.");
|
427
378
|
|
428
379
|
heap->d = dheap_value_to_int_d(d);
|
429
|
-
dheap_set_capa(heap,
|
380
|
+
dheap_set_capa(heap, dheap_value_to_capa(capa));
|
381
|
+
#ifdef DHEAP_MAP
|
382
|
+
if (RTEST(map)) heap->indexes = rb_hash_new();
|
383
|
+
#endif
|
430
384
|
|
431
385
|
return self;
|
432
386
|
}
|
@@ -435,18 +389,19 @@ dheap_initialize(VALUE self, VALUE d, VALUE capa) {
|
|
435
389
|
static VALUE
|
436
390
|
dheap_initialize_copy(VALUE copy, VALUE orig)
|
437
391
|
{
|
438
|
-
dheap_t *heap_copy;
|
392
|
+
dheap_t *heap_copy = get_dheap_struct_unfrozen(copy);
|
439
393
|
dheap_t *heap_orig = get_dheap_struct(orig);
|
440
394
|
|
441
|
-
rb_check_frozen(copy);
|
442
|
-
TypedData_Get_Struct(copy, dheap_t, &dheap_data_type, heap_copy);
|
443
|
-
|
444
395
|
heap_copy->d = heap_orig->d;
|
445
396
|
|
446
397
|
dheap_set_capa(heap_copy, heap_orig->capa);
|
447
398
|
heap_copy->size = heap_orig->size;
|
448
399
|
if (heap_copy->size)
|
449
400
|
MEMCPY(heap_copy->entries, heap_orig->entries, ENTRY, heap_orig->size);
|
401
|
+
#ifdef DHEAP_MAP
|
402
|
+
if (RTEST(heap_orig->indexes))
|
403
|
+
heap_copy->indexes = rb_hash_dup(heap_orig->indexes);
|
404
|
+
#endif
|
450
405
|
|
451
406
|
return copy;
|
452
407
|
}
|
@@ -457,75 +412,54 @@ dheap_initialize_copy(VALUE copy, VALUE orig)
|
|
457
412
|
*
|
458
413
|
********************************************************************/
|
459
414
|
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
return LONG2NUM(index);
|
480
|
-
}
|
415
|
+
#define DHEAP_SIFT_UP(T, heap, i) \
|
416
|
+
do { \
|
417
|
+
size_t sift_idx = i; \
|
418
|
+
ENTRY entry = DHEAP_GET(heap, sift_idx); \
|
419
|
+
ASSERT_DHEAP_IDX_OK(heap, sift_idx); \
|
420
|
+
for (size_t parent_idx; 0 < sift_idx; sift_idx = parent_idx) { \
|
421
|
+
parent_idx = DHEAP_IDX_PARENT(heap, sift_idx); \
|
422
|
+
if (CMP_LTE(DHEAP_SCORE((heap), parent_idx), entry.score)) break; \
|
423
|
+
DHEAP_SET(T, heap, sift_idx, DHEAP_GET(heap, parent_idx)); \
|
424
|
+
} \
|
425
|
+
DHEAP_SET(T, heap, sift_idx, entry); \
|
426
|
+
} while (0)
|
427
|
+
|
428
|
+
static inline size_t
|
429
|
+
dheap_min_child(dheap_t *heap, size_t parent, size_t last_index)
|
430
|
+
{
|
431
|
+
size_t min_child = DHEAP_IDX_CHILD_0(heap, parent);
|
432
|
+
size_t last_sib = DHEAP_IDX_CHILD_D(heap, parent);
|
433
|
+
if (UNLIKELY(last_index < last_sib)) last_sib = last_index;
|
481
434
|
|
482
|
-
|
483
|
-
|
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))) {
|
435
|
+
for (size_t sibidx = min_child + 1; sibidx <= last_sib; ++sibidx) {
|
436
|
+
if (CMP_LT(DHEAP_SCORE(heap, sibidx), DHEAP_SCORE(heap, min_child))) {
|
494
437
|
min_child = sibidx;
|
495
438
|
}
|
496
439
|
}
|
497
440
|
return min_child;
|
498
441
|
}
|
499
442
|
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
// child is smaller: swap and continue sifting down
|
522
|
-
heap->entries[index] = heap->entries[min_child];
|
523
|
-
index = min_child;
|
524
|
-
}
|
525
|
-
heap->entries[index] = entry;
|
526
|
-
// debug(rb_sprintf("sifted (%"PRIsVALUE", %d, %ld)", heap->values, heap->d, index));
|
527
|
-
}
|
528
|
-
}
|
443
|
+
#define DHEAP_CAN_SIFT_DOWN(heap, index, last_index) \
|
444
|
+
(LIKELY(1 <= last_index && index <= DHEAP_IDX_PARENT(heap, last_index)))
|
445
|
+
|
446
|
+
#define DHEAP_SIFT_DOWN(T, heap, i) \
|
447
|
+
do { \
|
448
|
+
size_t sift_idx = i; \
|
449
|
+
size_t last_idx = DHEAP_IDX_LAST(heap); \
|
450
|
+
ASSERT_DHEAP_IDX_OK(heap, sift_idx); \
|
451
|
+
if (DHEAP_CAN_SIFT_DOWN(heap, sift_idx, last_idx)) { \
|
452
|
+
ENTRY entry = heap->entries[sift_idx]; \
|
453
|
+
size_t last_parent = DHEAP_IDX_PARENT(heap, last_idx); \
|
454
|
+
while (sift_idx <= last_parent) { \
|
455
|
+
size_t min_child = dheap_min_child(heap, sift_idx, last_idx); \
|
456
|
+
if (CMP_LTE(entry.score, DHEAP_SCORE(heap, min_child))) break; \
|
457
|
+
DHEAP_SET(T, heap, sift_idx, (heap)->entries[min_child]); \
|
458
|
+
sift_idx = min_child; \
|
459
|
+
} \
|
460
|
+
DHEAP_SET(T, heap, sift_idx, entry); \
|
461
|
+
} \
|
462
|
+
} while (0)
|
529
463
|
|
530
464
|
/********************************************************************
|
531
465
|
*
|
@@ -540,9 +474,11 @@ static VALUE
|
|
540
474
|
dheap_size(VALUE self)
|
541
475
|
{
|
542
476
|
dheap_t *heap = get_dheap_struct(self);
|
543
|
-
return
|
477
|
+
return ULONG2NUM(heap->size);
|
544
478
|
}
|
545
479
|
|
480
|
+
#define DHEAP_EMPTY_P(heap) UNLIKELY((heap)->size <= 0)
|
481
|
+
|
546
482
|
/*
|
547
483
|
* @return [Boolean] if the heap is empty
|
548
484
|
*/
|
@@ -550,7 +486,7 @@ static VALUE
|
|
550
486
|
dheap_empty_p(VALUE self)
|
551
487
|
{
|
552
488
|
dheap_t *heap = get_dheap_struct(self);
|
553
|
-
return heap
|
489
|
+
return DHEAP_EMPTY_P(heap) ? Qtrue : Qfalse;
|
554
490
|
}
|
555
491
|
|
556
492
|
/*
|
@@ -569,13 +505,47 @@ dheap_attr_d(VALUE self)
|
|
569
505
|
*
|
570
506
|
********************************************************************/
|
571
507
|
|
508
|
+
#define DHEAP_PUSH(T, heap, entry) \
|
509
|
+
do { \
|
510
|
+
dheap_ensure_room_for_push(heap, 1); \
|
511
|
+
DHEAP_SET(T, heap, (heap)->size, *(entry)); \
|
512
|
+
++heap->size; \
|
513
|
+
DHEAP_SIFT_UP(T, heap, DHEAP_IDX_LAST(heap)); \
|
514
|
+
} while (0)
|
515
|
+
|
572
516
|
static inline void
|
573
|
-
dheap_push_entry(
|
574
|
-
|
575
|
-
heap
|
576
|
-
|
577
|
-
|
517
|
+
dheap_push_entry(VALUE self, ENTRY *entry)
|
518
|
+
{
|
519
|
+
dheap_t *heap = get_dheap_struct_unfrozen(self);
|
520
|
+
DHEAP_PUSH(dheap, heap, entry);
|
521
|
+
}
|
522
|
+
|
523
|
+
#ifdef DHEAP_MAP
|
524
|
+
static inline void
|
525
|
+
dheapmap_update_entry(dheap_t *heap, size_t index, ENTRY *entry)
|
526
|
+
{
|
527
|
+
SCORE prev = DHEAP_SCORE(heap, index);
|
528
|
+
DHEAP_SET(dheapmap, heap, index, *entry);
|
529
|
+
if (CMP_LT(prev, entry->score)) {
|
530
|
+
DHEAP_SIFT_DOWN(dheapmap, heap, index);
|
531
|
+
} else {
|
532
|
+
DHEAP_SIFT_UP(dheapmap, heap, index);
|
533
|
+
}
|
534
|
+
}
|
535
|
+
|
536
|
+
static inline void
|
537
|
+
dheapmap_push_entry(VALUE self, ENTRY *entry)
|
538
|
+
{
|
539
|
+
dheap_t *heap = get_dheap_struct_unfrozen(self);
|
540
|
+
VALUE idxval = rb_hash_lookup2(heap->indexes, entry->value, Qfalse);
|
541
|
+
if (idxval) {
|
542
|
+
size_t index = NUM2ULONG(idxval);
|
543
|
+
dheapmap_update_entry(heap, index, entry);
|
544
|
+
return;
|
545
|
+
}
|
546
|
+
DHEAP_PUSH(dheapmap, heap, entry);
|
578
547
|
}
|
548
|
+
#endif
|
579
549
|
|
580
550
|
/*
|
581
551
|
* Inserts a value into the heap, using a score to determine sort-order.
|
@@ -590,26 +560,42 @@ dheap_push_entry(dheap_t *heap, ENTRY *entry) {
|
|
590
560
|
* @return [self]
|
591
561
|
*/
|
592
562
|
static VALUE
|
593
|
-
dheap_insert(VALUE self, VALUE score, VALUE value)
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
entry.value = value;
|
600
|
-
dheap_push_entry(heap, &entry);
|
563
|
+
dheap_insert(VALUE self, VALUE score, VALUE value)
|
564
|
+
{
|
565
|
+
ENTRY entry = { VAL2SCORE(score), value };
|
566
|
+
dheap_push_entry(self, &entry);
|
567
|
+
return self;
|
568
|
+
}
|
601
569
|
|
570
|
+
#ifdef DHEAP_MAP
|
571
|
+
/* (see DHeap#insert) */
|
572
|
+
static VALUE
|
573
|
+
dheapmap_insert(VALUE self, VALUE score, VALUE value)
|
574
|
+
{
|
575
|
+
ENTRY entry = { VAL2SCORE(score), value };
|
576
|
+
dheapmap_push_entry(self, &entry);
|
602
577
|
return self;
|
603
578
|
}
|
579
|
+
#endif
|
580
|
+
|
581
|
+
static inline ENTRY
|
582
|
+
dheap_push_args_to_entry(int argc, VALUE *argv)
|
583
|
+
{
|
584
|
+
ENTRY entry;
|
585
|
+
rb_check_arity(argc, 1, 2);
|
586
|
+
entry.value = argv[0];
|
587
|
+
entry.score = VAL2SCORE(argc < 2 ? entry.value : argv[1]);
|
588
|
+
return entry;
|
589
|
+
}
|
604
590
|
|
605
591
|
/*
|
606
592
|
* @overload push(value, score = value)
|
607
593
|
*
|
608
594
|
* Push a value onto heap, using a score to determine sort-order.
|
609
595
|
*
|
610
|
-
* Value comes first because the separate score is optional, and because it
|
611
|
-
* like a more natural variation on +Array#push+ or +Queue#enq+. If a
|
612
|
-
* isn't provided, the value must be an Integer or can be cast with
|
596
|
+
* Value comes first because the separate score is optional, and because it
|
597
|
+
* feels like a more natural variation on +Array#push+ or +Queue#enq+. If a
|
598
|
+
* score isn't provided, the value must be an Integer or can be cast with
|
613
599
|
* +Float(value)+.
|
614
600
|
*
|
615
601
|
* Time complexity: <b>O(log n / log d)</b> <i>(worst-case)</i>
|
@@ -620,18 +606,23 @@ dheap_insert(VALUE self, VALUE score, VALUE value) {
|
|
620
606
|
* @return [self]
|
621
607
|
*/
|
622
608
|
static VALUE
|
623
|
-
dheap_push(int argc, VALUE *argv, VALUE self)
|
624
|
-
|
625
|
-
ENTRY entry;
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
entry.value = argv[0];
|
630
|
-
entry.score = VAL2SCORE(argc < 2 ? entry.value : argv[1]);
|
631
|
-
dheap_push_entry(heap, &entry);
|
609
|
+
dheap_push(int argc, VALUE *argv, VALUE self)
|
610
|
+
{
|
611
|
+
ENTRY entry = dheap_push_args_to_entry(argc, argv);
|
612
|
+
dheap_push_entry(self, &entry);
|
613
|
+
return self;
|
614
|
+
}
|
632
615
|
|
616
|
+
#ifdef DHEAP_MAP
|
617
|
+
/* (see DHeap#push) */
|
618
|
+
static VALUE
|
619
|
+
dheapmap_push(int argc, VALUE *argv, VALUE self)
|
620
|
+
{
|
621
|
+
ENTRY entry = dheap_push_args_to_entry(argc, argv);
|
622
|
+
dheapmap_push_entry(self, &entry);
|
633
623
|
return self;
|
634
624
|
}
|
625
|
+
#endif
|
635
626
|
|
636
627
|
/*
|
637
628
|
* Pushes a value onto the heap.
|
@@ -645,17 +636,23 @@ dheap_push(int argc, VALUE *argv, VALUE self) {
|
|
645
636
|
* @return [self]
|
646
637
|
*/
|
647
638
|
static VALUE
|
648
|
-
|
649
|
-
|
650
|
-
ENTRY entry;
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
entry.value = value;
|
655
|
-
dheap_push_entry(heap, &entry);
|
639
|
+
dheap_lshift(VALUE self, VALUE value)
|
640
|
+
{
|
641
|
+
ENTRY entry = { VAL2SCORE(value), value };
|
642
|
+
dheap_push_entry(self, &entry);
|
643
|
+
return self;
|
644
|
+
}
|
656
645
|
|
646
|
+
#ifdef DHEAP_MAP
|
647
|
+
/* (see DHeap#<<) */
|
648
|
+
static VALUE
|
649
|
+
dheapmap_lshift(VALUE self, VALUE value)
|
650
|
+
{
|
651
|
+
ENTRY entry = { VAL2SCORE(value), value };
|
652
|
+
dheapmap_push_entry(self, &entry);
|
657
653
|
return self;
|
658
654
|
}
|
655
|
+
#endif
|
659
656
|
|
660
657
|
/********************************************************************
|
661
658
|
*
|
@@ -663,23 +660,15 @@ dheap_left_shift(VALUE self, VALUE value) {
|
|
663
660
|
*
|
664
661
|
********************************************************************/
|
665
662
|
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
static inline VALUE
|
677
|
-
dheap_pop0(dheap_t *heap)
|
678
|
-
{
|
679
|
-
VALUE popped = DHEAP_VALUE(heap, 0);
|
680
|
-
dheap_del0(heap);
|
681
|
-
return popped;
|
682
|
-
}
|
663
|
+
#define PEEK_VALUE(heap) DHEAP_VALUE(heap, 0)
|
664
|
+
#define PEEK_SCORE(heap) DHEAP_SCORE(heap, 0)
|
665
|
+
#define PEEK_WITH_SCORE(heap) DHEAP_ENTRY_ARY(heap, 0)
|
666
|
+
#define PEEK_LT_P(heap, max_score) _PEEK_CMP_P(heap, CMP_LT, max_score)
|
667
|
+
#define PEEK_LTE_P(heap, max_score) _PEEK_CMP_P(heap, CMP_LTE, max_score)
|
668
|
+
#define _PEEK_CMP_P(heap, cmp, score) \
|
669
|
+
((!DHEAP_EMPTY_P(heap) && cmp(PEEK_SCORE(heap), (score))) \
|
670
|
+
? PEEK_VALUE(heap) \
|
671
|
+
: 0)
|
683
672
|
|
684
673
|
/*
|
685
674
|
* Returns the next value on the heap, and its score, without popping it
|
@@ -694,11 +683,12 @@ static VALUE
|
|
694
683
|
dheap_peek_with_score(VALUE self)
|
695
684
|
{
|
696
685
|
dheap_t *heap = get_dheap_struct(self);
|
697
|
-
return
|
686
|
+
return PEEK_WITH_SCORE(heap);
|
698
687
|
}
|
699
688
|
|
700
689
|
/*
|
701
|
-
* Returns the next score on the heap, without the value and without popping
|
690
|
+
* Returns the next score on the heap, without the value and without popping
|
691
|
+
* it.
|
702
692
|
*
|
703
693
|
* Time complexity: <b>O(1)</b> <i>(worst-case)</i>
|
704
694
|
* @return [nil, Numeric] the next score, if there is one
|
@@ -710,8 +700,8 @@ static VALUE
|
|
710
700
|
dheap_peek_score(VALUE self)
|
711
701
|
{
|
712
702
|
dheap_t *heap = get_dheap_struct(self);
|
713
|
-
if (
|
714
|
-
return SCORE2NUM(
|
703
|
+
if (DHEAP_EMPTY_P(heap)) return Qnil;
|
704
|
+
return SCORE2NUM(PEEK_SCORE(heap));
|
715
705
|
}
|
716
706
|
|
717
707
|
/*
|
@@ -727,9 +717,52 @@ static VALUE
|
|
727
717
|
dheap_peek(VALUE self)
|
728
718
|
{
|
729
719
|
dheap_t *heap = get_dheap_struct(self);
|
730
|
-
|
720
|
+
if (DHEAP_EMPTY_P(heap)) return Qnil;
|
721
|
+
return PEEK_VALUE(heap);
|
731
722
|
}
|
732
723
|
|
724
|
+
#define DHEAP_POP_COMMON_INIT(self) \
|
725
|
+
dheap_t *heap = get_dheap_struct_unfrozen(self); \
|
726
|
+
if (DHEAP_EMPTY_P(heap)) return Qnil;
|
727
|
+
|
728
|
+
#define DHEAP_DELETE_0(T, heap) \
|
729
|
+
do { \
|
730
|
+
_DELETE_ENTRY(T, heap, 0); \
|
731
|
+
if (0 < --(heap)->size) { \
|
732
|
+
DHEAP_SET(T, (heap), 0, (heap)->entries[(heap)->size]); \
|
733
|
+
DHEAP_SIFT_DOWN(T, (heap), 0); \
|
734
|
+
} \
|
735
|
+
} while (0)
|
736
|
+
|
737
|
+
#define _DELETE_ENTRY(T, heap, idx) _DELETE_ENTRY_##T(heap, idx)
|
738
|
+
#define _DELETE_ENTRY_dheap(heap, idx) /* noop */
|
739
|
+
#define _DELETE_ENTRY_dheapmap(heap, idx) \
|
740
|
+
rb_hash_delete(heap->indexes, DHEAP_VALUE(heap, idx))
|
741
|
+
|
742
|
+
#define POP(T, heap, popped) _POP(T, VALUE, heap, popped)
|
743
|
+
#define POP_WITH_SCORE(T, heap, popped) _POP(T, WITH_SCORE, heap, popped)
|
744
|
+
#define POP_LT(T, heap, max, popped) _POP_CMP(T, heap, LT, max, popped)
|
745
|
+
#define POP_LTE(T, heap, max, popped) _POP_CMP(T, heap, LTE, max, popped)
|
746
|
+
|
747
|
+
#define _POP_CMP(T, heap, cmp, cmp_score, popped) \
|
748
|
+
do { \
|
749
|
+
if ((*(popped) = PEEK_##cmp##_P(heap, cmp_score))) { \
|
750
|
+
DHEAP_DELETE_0(T, heap); \
|
751
|
+
} else { \
|
752
|
+
*(popped) = Qnil; \
|
753
|
+
} \
|
754
|
+
} while (0)
|
755
|
+
|
756
|
+
#define _POP(T, peek_type, heap, popped) \
|
757
|
+
do { \
|
758
|
+
if (DHEAP_EMPTY_P(heap)) { \
|
759
|
+
*(popped) = Qnil; \
|
760
|
+
} else { \
|
761
|
+
*(popped) = PEEK_##peek_type(heap); \
|
762
|
+
DHEAP_DELETE_0(T, heap); \
|
763
|
+
} \
|
764
|
+
} while (0)
|
765
|
+
|
733
766
|
/*
|
734
767
|
* Pops the minimum value from the top of the heap
|
735
768
|
*
|
@@ -745,10 +778,23 @@ dheap_peek(VALUE self)
|
|
745
778
|
static VALUE
|
746
779
|
dheap_pop(VALUE self)
|
747
780
|
{
|
748
|
-
dheap_t *heap =
|
749
|
-
|
750
|
-
|
781
|
+
dheap_t *heap = get_dheap_struct_unfrozen(self);
|
782
|
+
VALUE popped;
|
783
|
+
POP(dheap, heap, &popped);
|
784
|
+
return popped;
|
785
|
+
}
|
786
|
+
|
787
|
+
#ifdef DHEAP_MAP
|
788
|
+
/* (see DHeap#pop) */
|
789
|
+
static VALUE
|
790
|
+
dheapmap_pop(VALUE self)
|
791
|
+
{
|
792
|
+
dheap_t *heap = get_dheap_struct_unfrozen(self);
|
793
|
+
VALUE popped;
|
794
|
+
POP(dheapmap, heap, &popped);
|
795
|
+
return popped;
|
751
796
|
}
|
797
|
+
#endif
|
752
798
|
|
753
799
|
/*
|
754
800
|
* Pops the minimum value from the top of the heap, along with its score.
|
@@ -763,13 +809,27 @@ dheap_pop(VALUE self)
|
|
763
809
|
static VALUE
|
764
810
|
dheap_pop_with_score(VALUE self)
|
765
811
|
{
|
766
|
-
dheap_t *heap =
|
767
|
-
VALUE
|
768
|
-
|
769
|
-
|
770
|
-
return ary;
|
812
|
+
dheap_t *heap = get_dheap_struct_unfrozen(self);
|
813
|
+
VALUE popped;
|
814
|
+
POP_WITH_SCORE(dheap, heap, &popped);
|
815
|
+
return popped;
|
771
816
|
}
|
772
817
|
|
818
|
+
#ifdef DHEAP_MAP
|
819
|
+
/* (see DHeap#pop_with_score) */
|
820
|
+
static VALUE
|
821
|
+
dheapmap_pop_with_score(VALUE self)
|
822
|
+
{
|
823
|
+
dheap_t *heap = get_dheap_struct_unfrozen(self);
|
824
|
+
VALUE popped;
|
825
|
+
POP_WITH_SCORE(dheapmap, heap, &popped);
|
826
|
+
return popped;
|
827
|
+
}
|
828
|
+
#endif
|
829
|
+
|
830
|
+
#define DHEAP_POP_IF(heap, cmp, max_score) \
|
831
|
+
if (!cmp(PEEK_SCORE(heap), VAL2SCORE(max_score))) return Qnil
|
832
|
+
|
773
833
|
/*
|
774
834
|
* Pops the minimum value only if it is less than or equal to a max score.
|
775
835
|
*
|
@@ -787,13 +847,24 @@ dheap_pop_with_score(VALUE self)
|
|
787
847
|
static VALUE
|
788
848
|
dheap_pop_lte(VALUE self, VALUE max_score)
|
789
849
|
{
|
790
|
-
dheap_t *heap =
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
return dheap_pop0(heap);
|
850
|
+
dheap_t *heap = get_dheap_struct_unfrozen(self);
|
851
|
+
VALUE popped;
|
852
|
+
POP_LTE(dheap, heap, VAL2SCORE(max_score), &popped);
|
853
|
+
return popped;
|
795
854
|
}
|
796
855
|
|
856
|
+
#ifdef DHEAP_MAP
|
857
|
+
/* (see DHeap#pop_lte) */
|
858
|
+
static VALUE
|
859
|
+
dheapmap_pop_lte(VALUE self, VALUE max_score)
|
860
|
+
{
|
861
|
+
dheap_t *heap = get_dheap_struct_unfrozen(self);
|
862
|
+
VALUE popped;
|
863
|
+
POP_LTE(dheapmap, heap, VAL2SCORE(max_score), &popped);
|
864
|
+
return popped;
|
865
|
+
}
|
866
|
+
#endif
|
867
|
+
|
797
868
|
/*
|
798
869
|
* Pops the minimum value only if it is less than a max score.
|
799
870
|
*
|
@@ -811,31 +882,39 @@ dheap_pop_lte(VALUE self, VALUE max_score)
|
|
811
882
|
static VALUE
|
812
883
|
dheap_pop_lt(VALUE self, VALUE max_score)
|
813
884
|
{
|
814
|
-
dheap_t *heap =
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
return dheap_pop0(heap);
|
885
|
+
dheap_t *heap = get_dheap_struct_unfrozen(self);
|
886
|
+
VALUE popped;
|
887
|
+
POP_LT(dheap, heap, VAL2SCORE(max_score), &popped);
|
888
|
+
return popped;
|
819
889
|
}
|
820
890
|
|
821
|
-
#
|
822
|
-
|
823
|
-
|
891
|
+
#ifdef DHEAP_MAP
|
892
|
+
/* (see DHeap#pop_lt) */
|
824
893
|
static VALUE
|
825
|
-
|
894
|
+
dheapmap_pop_lt(VALUE self, VALUE max_score)
|
826
895
|
{
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
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;
|
896
|
+
dheap_t *heap = get_dheap_struct_unfrozen(self);
|
897
|
+
VALUE popped;
|
898
|
+
POP_LT(dheapmap, heap, VAL2SCORE(max_score), &popped);
|
899
|
+
return popped;
|
838
900
|
}
|
901
|
+
#endif
|
902
|
+
|
903
|
+
#define POP_ALL_BELOW(T, heap, max_score, array) \
|
904
|
+
do { \
|
905
|
+
VALUE val = Qnil; \
|
906
|
+
if (RB_TYPE_P(array, T_ARRAY)) { \
|
907
|
+
while ((val = PEEK_LT_P(heap, max_score))) { \
|
908
|
+
DHEAP_DELETE_0(T, heap); \
|
909
|
+
rb_ary_push(array, val); \
|
910
|
+
} \
|
911
|
+
} else { \
|
912
|
+
while ((val = PEEK_LT_P(heap, max_score))) { \
|
913
|
+
DHEAP_DELETE_0(T, heap); \
|
914
|
+
rb_funcall(array, id_lshift, 1, val); \
|
915
|
+
} \
|
916
|
+
} \
|
917
|
+
} while (0)
|
839
918
|
|
840
919
|
/*
|
841
920
|
* @overload pop_all_below(max_score, receiver = [])
|
@@ -856,18 +935,12 @@ dheap_pop_all_below0(dheap_t *heap, SCORE max_score, VALUE array)
|
|
856
935
|
static VALUE
|
857
936
|
dheap_pop_all_below(int argc, VALUE *argv, VALUE self)
|
858
937
|
{
|
859
|
-
dheap_t *heap
|
860
|
-
SCORE
|
861
|
-
VALUE
|
862
|
-
rb_check_frozen(self);
|
938
|
+
dheap_t *heap = get_dheap_struct_unfrozen(self);
|
939
|
+
SCORE max_score = (argc) ? VAL2SCORE(argv[0]) : 0.0;
|
940
|
+
VALUE array = (argc == 1) ? rb_ary_new() : argv[1];
|
863
941
|
rb_check_arity(argc, 1, 2);
|
864
|
-
max_score
|
865
|
-
|
866
|
-
array = rb_ary_new();
|
867
|
-
} else {
|
868
|
-
array = argv[1];
|
869
|
-
}
|
870
|
-
return dheap_pop_all_below0(heap, max_score, array);
|
942
|
+
DHEAP_DISPATCH_STMT(heap, POP_ALL_BELOW, max_score, array);
|
943
|
+
return array;
|
871
944
|
}
|
872
945
|
|
873
946
|
/********************************************************************
|
@@ -876,6 +949,17 @@ dheap_pop_all_below(int argc, VALUE *argv, VALUE self)
|
|
876
949
|
*
|
877
950
|
********************************************************************/
|
878
951
|
|
952
|
+
static VALUE
|
953
|
+
dheap_to_a(VALUE self)
|
954
|
+
{
|
955
|
+
dheap_t *heap = get_dheap_struct(self);
|
956
|
+
VALUE array = rb_ary_new_capa(heap->size);
|
957
|
+
for (size_t i = 0; i < heap->size; i++) {
|
958
|
+
rb_ary_push(array, DHEAP_ENTRY_ARY(heap, i));
|
959
|
+
}
|
960
|
+
return array;
|
961
|
+
}
|
962
|
+
|
879
963
|
/*
|
880
964
|
* Clears all values from the heap, leaving it empty.
|
881
965
|
*
|
@@ -884,14 +968,64 @@ dheap_pop_all_below(int argc, VALUE *argv, VALUE self)
|
|
884
968
|
static VALUE
|
885
969
|
dheap_clear(VALUE self)
|
886
970
|
{
|
887
|
-
dheap_t *heap =
|
888
|
-
|
889
|
-
if (0 < heap->size) {
|
971
|
+
dheap_t *heap = get_dheap_struct_unfrozen(self);
|
972
|
+
if (!DHEAP_EMPTY_P(heap)) {
|
890
973
|
heap->size = 0;
|
974
|
+
#ifdef DHEAP_MAP
|
975
|
+
if (DHEAPMAP_P(heap)) rb_hash_clear(heap->indexes);
|
976
|
+
#endif
|
891
977
|
}
|
892
978
|
return self;
|
893
979
|
}
|
894
980
|
|
981
|
+
/********************************************************************
|
982
|
+
*
|
983
|
+
* DHeap::Map methods
|
984
|
+
*
|
985
|
+
********************************************************************/
|
986
|
+
|
987
|
+
#ifdef DHEAP_MAP
|
988
|
+
|
989
|
+
/*
|
990
|
+
* Retrieves the score that has been assigned to a heap member.
|
991
|
+
*
|
992
|
+
* Time complexity: <b>O(1)</b>
|
993
|
+
*
|
994
|
+
* @param object [Object] an object to lookup
|
995
|
+
* @return [Float,Integer,nil] the score associated with the object,
|
996
|
+
* or nil if the object isn't a member
|
997
|
+
*/
|
998
|
+
static VALUE
|
999
|
+
dheapmap_aref(VALUE self, VALUE object)
|
1000
|
+
{
|
1001
|
+
dheap_t *heap = get_dheap_struct(self);
|
1002
|
+
VALUE idxval = rb_hash_lookup2(heap->indexes, object, Qfalse);
|
1003
|
+
if (idxval) {
|
1004
|
+
size_t index = NUM2ULONG(idxval);
|
1005
|
+
return SCORE2NUM(DHEAP_SCORE(heap, index));
|
1006
|
+
}
|
1007
|
+
return Qnil;
|
1008
|
+
}
|
1009
|
+
|
1010
|
+
/*
|
1011
|
+
* Assign a score to an object, adding it to the heap or updating as necessary.
|
1012
|
+
*
|
1013
|
+
* Time complexity: <b>O(log n)</b> (score decrease will be faster than
|
1014
|
+
* score increase)
|
1015
|
+
*
|
1016
|
+
* @param object [Object] an object to lookup
|
1017
|
+
* @param score [Integer,#to_f] the score to set
|
1018
|
+
* @return [Float,Integer] the score
|
1019
|
+
*/
|
1020
|
+
static VALUE
|
1021
|
+
dheapmap_aset(VALUE self, VALUE object, VALUE score)
|
1022
|
+
{
|
1023
|
+
dheapmap_insert(self, score, object);
|
1024
|
+
return score;
|
1025
|
+
}
|
1026
|
+
|
1027
|
+
#endif
|
1028
|
+
|
895
1029
|
/********************************************************************
|
896
1030
|
*
|
897
1031
|
* DHeap setup
|
@@ -902,14 +1036,26 @@ void
|
|
902
1036
|
Init_d_heap(void)
|
903
1037
|
{
|
904
1038
|
VALUE rb_cDHeap = rb_define_class("DHeap", rb_cObject);
|
1039
|
+
#ifdef DHEAP_MAP
|
1040
|
+
VALUE rb_cDHeapMap = rb_define_class_under(rb_cDHeap, "Map", rb_cDHeap);
|
1041
|
+
#endif
|
905
1042
|
|
906
|
-
id_cmp
|
907
|
-
id_abs
|
1043
|
+
id_cmp = rb_intern_const("<=>");
|
1044
|
+
id_abs = rb_intern_const("abs");
|
908
1045
|
id_lshift = rb_intern_const("<<");
|
909
|
-
|
1046
|
+
id_uminus = rb_intern_const("-@");
|
910
1047
|
|
911
1048
|
rb_define_alloc_func(rb_cDHeap, dheap_s_alloc);
|
912
1049
|
|
1050
|
+
#ifdef DHEAP_MAP
|
1051
|
+
# define def_override_inherited(rb_name, c_name, argc) \
|
1052
|
+
rb_define_method(rb_cDHeap, rb_name, dheap_##c_name, argc); \
|
1053
|
+
rb_define_method(rb_cDHeapMap, rb_name, dheapmap_##c_name, argc);
|
1054
|
+
#else
|
1055
|
+
# define def_override_inherited(rb_name, c_name, argc) \
|
1056
|
+
rb_define_method(rb_cDHeap, rb_name, dheap_##c_name, argc);
|
1057
|
+
#endif
|
1058
|
+
|
913
1059
|
/*
|
914
1060
|
* This is based on INT_MAX. But it is very very unlikely you will want a
|
915
1061
|
* large value for d. The tradeoff is that higher d values give faster push
|
@@ -917,12 +1063,12 @@ Init_d_heap(void)
|
|
917
1063
|
* stick with the default. If you expect more pushes than pops, it might be
|
918
1064
|
* worthwhile to increase d.
|
919
1065
|
*/
|
920
|
-
rb_define_const(rb_cDHeap, "MAX_D",
|
1066
|
+
rb_define_const(rb_cDHeap, "MAX_D", INT2NUM(DHEAP_MAX_D));
|
921
1067
|
|
922
1068
|
/*
|
923
1069
|
* d=4 uses the fewest comparisons for (worst case) insert + delete-min.
|
924
1070
|
*/
|
925
|
-
rb_define_const(rb_cDHeap, "DEFAULT_D",
|
1071
|
+
rb_define_const(rb_cDHeap, "DEFAULT_D", INT2NUM(DHEAP_DEFAULT_D));
|
926
1072
|
|
927
1073
|
/*
|
928
1074
|
* The default heap capacity. The heap grows automatically as necessary, so
|
@@ -930,26 +1076,31 @@ Init_d_heap(void)
|
|
930
1076
|
*/
|
931
1077
|
rb_define_const(rb_cDHeap, "DEFAULT_CAPA", INT2NUM(DHEAP_DEFAULT_CAPA));
|
932
1078
|
|
933
|
-
rb_define_private_method(rb_cDHeap, "__init_without_kw__",
|
1079
|
+
rb_define_private_method(rb_cDHeap, "__init_without_kw__", dheap_init, 3);
|
934
1080
|
rb_define_method(rb_cDHeap, "initialize_copy", dheap_initialize_copy, 1);
|
935
1081
|
|
936
|
-
rb_define_method(rb_cDHeap, "d",
|
937
|
-
rb_define_method(rb_cDHeap, "size",
|
938
|
-
rb_define_method(rb_cDHeap, "empty?",
|
939
|
-
rb_define_method(rb_cDHeap, "
|
940
|
-
|
941
|
-
rb_define_method(rb_cDHeap, "clear", dheap_clear, 0);
|
942
|
-
rb_define_method(rb_cDHeap, "insert", dheap_insert, 2);
|
943
|
-
rb_define_method(rb_cDHeap, "push", dheap_push, -1);
|
944
|
-
rb_define_method(rb_cDHeap, "<<", dheap_left_shift, 1);
|
945
|
-
rb_define_method(rb_cDHeap, "pop", dheap_pop, 0);
|
1082
|
+
rb_define_method(rb_cDHeap, "d", dheap_attr_d, 0);
|
1083
|
+
rb_define_method(rb_cDHeap, "size", dheap_size, 0);
|
1084
|
+
rb_define_method(rb_cDHeap, "empty?", dheap_empty_p, 0);
|
1085
|
+
rb_define_method(rb_cDHeap, "to_a", dheap_to_a, 0);
|
946
1086
|
|
947
|
-
rb_define_method(rb_cDHeap, "
|
948
|
-
rb_define_method(rb_cDHeap, "
|
1087
|
+
rb_define_method(rb_cDHeap, "clear", dheap_clear, 0);
|
1088
|
+
rb_define_method(rb_cDHeap, "peek", dheap_peek, 0);
|
1089
|
+
rb_define_method(rb_cDHeap, "peek_score", dheap_peek_score, 0);
|
1090
|
+
rb_define_method(rb_cDHeap, "peek_with_score", dheap_peek_with_score, 0);
|
949
1091
|
rb_define_method(rb_cDHeap, "pop_all_below", dheap_pop_all_below, -1);
|
950
1092
|
|
951
|
-
|
952
|
-
|
953
|
-
|
1093
|
+
def_override_inherited("insert", insert, 2);
|
1094
|
+
def_override_inherited("push", push, -1);
|
1095
|
+
def_override_inherited("<<", lshift, 1);
|
954
1096
|
|
1097
|
+
def_override_inherited("pop", pop, 0);
|
1098
|
+
def_override_inherited("pop_lt", pop_lt, 1);
|
1099
|
+
def_override_inherited("pop_lte", pop_lte, 1);
|
1100
|
+
def_override_inherited("pop_with_score", pop_with_score, 0);
|
1101
|
+
|
1102
|
+
#ifdef DHEAP_MAP
|
1103
|
+
rb_define_method(rb_cDHeapMap, "[]", dheapmap_aref, 1);
|
1104
|
+
rb_define_method(rb_cDHeapMap, "[]=", dheapmap_aset, 2);
|
1105
|
+
#endif
|
955
1106
|
}
|