d_heap 0.6.1 → 0.7.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/.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
|
}
|