priority_queue_cxx17 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8a841223729c1f0c7642e81085763cc03b257427e01c7955c8152a97b4995c08
4
+ data.tar.gz: 15778f008f8589dc011b2a4f8e7adbe1906016a404f89454f01385dc6184515e
5
+ SHA512:
6
+ metadata.gz: dc9b7a0d2136e36d27551c1b3042188d38c39dff9851dbfa2cd1125c3e6272a6db04a97303960188ea8db9dcebd886e8eacf43415827ca999b533c199c3c0af5
7
+ data.tar.gz: bacdb6ab15a1853e01bad9755d4bc78a7b99c8452b3e83433b013c0aac50250a9b0d20b55aa67f5daf44170dc693de3612490e95bb94e553708f6e08dd75df9a
@@ -0,0 +1,295 @@
1
+ # PriorityQueueCxx
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/priority_queue_cxx.png)](http://badge.fury.io/rb/priority_queue_cxx)
4
+ [![priority_queue_cxx API Documentation](https://www.omniref.com/ruby/gems/priority_queue_cxx.png)](https://www.omniref.com/ruby/gems/priority_queue_cxx)
5
+
6
+
7
+ *PriorityQueueCxx* provides a fast implementation of priority queues for ruby. Speed is achieved by exposing the c++ standard implementation through a light ruby wrapper. As a bigger project, the library may grow to provide a number of containers that are not in the standard ruby library and are presently only available as pure ruby libraries. Presently, however, the library includes a single class named PriorityQueue. More containers will be added as necessity arises. Contributors and feature requests are most welcome.
8
+
9
+ The library exposes a module named ```FastContainers``` (to be required using ```require 'fc'```) which provides the PriorityQueue class.
10
+
11
+ ## Installation
12
+
13
+ ```ruby
14
+ gem install 'priority_queue_cxx'
15
+ ```
16
+
17
+ ## Usage Example
18
+
19
+ ```ruby
20
+
21
+ require 'fc'
22
+ q = FastContainers::PriorityQueue.new(:max)
23
+ q.push("largest", 10)
24
+ q.push("smallest", 5)
25
+ q.top # => "largest"
26
+ q.top_key # => 10
27
+ q.pop
28
+ ```
29
+
30
+ ## How fast is it?
31
+
32
+ As far as I know, only one other library (the PriorityQueue gem) provides priority queues implemented as a C extension. This implies that the fc::PriorityQueue is a *lot* faster than most current alternatives and, as shown below, it compares favorably with the mentioned C extension as well.
33
+
34
+ To get an idea about how fast it is, below I provide a comparison of the time needed to push and pop a large number of elements into a priority queue. Each experiment compares FastContainers with other priority queues implementations. Since timings varies greatly among different implementations, the number of push/pop performed is chosen so to make the experiments to run for (at most) few minutes.
35
+
36
+ The following table summarizes the outputs, detailed results can be found in the next few sections. All libraries have been installed through the 'gem' command and executed using ruby v. 2.1.0.
37
+
38
+ | library | avg μs per push | avg μs per pop | avg μs per op |
39
+ |:--------|---------:|---------:|---------:|
40
+ | *priority_queue_cxx* | *0.456* | *1.138* | *0.797* |
41
+ | PriorityQueue | 2.09 | 5.186 | 3.638 |
42
+ | em-priority-queue | 3.56 | 8.32 | 5.94 |
43
+ | pqueue | 669.0 | 0.1 | 334.55|
44
+ | algorithms | 2584.6 | 29.6 |1307.1 |
45
+ | priority_queue | 1.4 |19134.6 |9568.0 |
46
+
47
+ where: results are sorted according to "avg μs per op" (higher in the list is better); μs stands for micro seconds; op stands for any operation (push or pop); the figures for priority_queue_cxx has been calculated with the results of experiments with PriorityQueue (the experiment with the highest number of operations).
48
+
49
+
50
+ ### Comparison with [algorithms (0.6.1)](http://rubygems.org/gems/algorithms) (50,000 push/pop)
51
+
52
+ ```ruby
53
+
54
+ require 'fc'
55
+ require 'algorithms'
56
+ require 'benchmark'
57
+
58
+ N = 50_000
59
+ algo_pq = Containers::PriorityQueue.new
60
+ fc_pq = FastContainers::PriorityQueue.new(:min)
61
+
62
+ Benchmark.bm do |bm|
63
+ bm.report('algo:push') { N.times { |n| algo_pq.push(n.to_s, rand) } }
64
+ bm.report('fc:push') { N.times { |n| fc_pq.push(n.to_s, rand) } }
65
+ bm.report('algo:pop') { N.times { algo_pq.pop } }
66
+ bm.report('fc:pop') { N.times { fc_pq.pop } }
67
+ end
68
+ ```
69
+
70
+ Output (reformatted):
71
+
72
+ | | user| system| total| real |
73
+ |:--------|---------:|---------:|---------:|-----------:|
74
+ |algorithms:push|122.200| 7.030|129.230|(129.173)|
75
+ |*fc:push* | *0.020*| *0.000*| *0.020*|*( 0.020)*|
76
+ |algorithms:pop | 1.460| 0.020| 1.480|( 1.476)|
77
+ |*fc:pop* | *0.030*| *0.000*| *0.030*|*( 0.030)*|
78
+
79
+ Summary: FastContainers::PriorityQueues (fc) are *6461.5 times faster* on pushes and *49.3 times faster* on pops.
80
+
81
+
82
+ ### Comparison with [priority_queue (0.2.0)](http://rubygems.org/gems/priority_queue) (50,000 push/pop)
83
+
84
+ ```ruby
85
+ require 'fc'
86
+ require 'priority_queue'
87
+ require 'benchmark'
88
+
89
+ N = 50_000
90
+ pq_pq = PriorityQueue.new
91
+ fc_pq = FastContainers::PriorityQueue.new(:min)
92
+
93
+ Benchmark.bm do |bm|
94
+ bm.report('pq:push') { N.times { |n| pq_pq[rand] << n.to_s } }
95
+ bm.report('fc:push') { N.times { |n| fc_pq.push(n.to_s, rand) } }
96
+ bm.report('pq:pop') { N.times { pq_pq.shift } }
97
+ bm.report('fc:pop') { N.times { fc_pq.pop } }
98
+ end
99
+ ```
100
+
101
+ Output (reformatted):
102
+
103
+ | | user| system| total| real |
104
+ |:--------|---------:|---------:|---------:|-----------:|
105
+ |priority_queue:push | 0.060 | 0.010 | 0.070 |( 0.062593)|
106
+ |*fc:push* | *0.020* | *0.000* | *0.020* |*( 0.018866)*|
107
+ |priority_queue:pop | 948.440 | 8.290 | 956.730 |(956.676601)|
108
+ |*fc:pop* | 0.040 | 0.000 | 0.040 |*( 0.032753)*|
109
+
110
+ Summary: FastContainers::PriorityQueues (fc) are *3.5 times faster* on pushes and *23918.25 times faster* on pops.
111
+
112
+ ### Comparison with [em-priority-queue (1.1.2)](http://rubygems.org/gems/em-priority-queue) (500,000 push/pop)
113
+
114
+ ```ruby
115
+ require 'fc'
116
+ require 'em-priority-queue'
117
+ require 'benchmark'
118
+
119
+ N = 500_000
120
+ em_pq = EM::PriorityQueue.new
121
+ fc_pq = FastContainers::PriorityQueue.new(:min)
122
+
123
+ Benchmark.bm do |bm|
124
+ bm.report('em:push') { N.times { |n| em_pq.push(n.to_s, rand) } }
125
+ bm.report('fc:push') { N.times { |n| fc_pq.push(n.to_s, rand) } }
126
+ bm.report('em:pop') { N.times { em_pq.pop {} } }
127
+ bm.report('fc:pop') { N.times { fc_pq.pop } }
128
+ end
129
+ ```
130
+
131
+ Output (reformatted):
132
+
133
+ | | user| system| total| real |
134
+ |:--------|---------:|---------:|---------:|-----------:|
135
+ |em-priority-queue:push |1.650 |0.130 | 1.780 | ( 1.895794) |
136
+ |*fc:push* |*0.190* |*0.020* | *0.210* | *( 0.224068)* |
137
+ |em-priority-queue:pop |3.980 |0.180 | 4.160 | ( 4.360084) |
138
+ |*fc:pop* |*0.380* |*0.000* | *0.380* | *( 0.381250)* |
139
+
140
+ Summary: FastContainers::PriorityQueue (fc) are *8.5 times faster* on pushes and *10.9 times faster* on pops.
141
+
142
+ ### Comparison with [pqueue (2.0.2)](http://rubygems.org/gems/pqueue) (100,000 push/pop)
143
+
144
+
145
+ ```ruby
146
+ require 'fc'
147
+ require 'pqueue'
148
+ require 'benchmark'
149
+
150
+ N = 100_000
151
+ pq_pq = PQueue.new { |x,y| x[1] <=> y[1] }
152
+ fc_pq = FastContainers::PriorityQueue.new(:min)
153
+
154
+ Benchmark.bm do |bm|
155
+ bm.report('pq:push') { N.times { |n| pq_pq.push([n,rand]) } }
156
+ bm.report('fc:push') { N.times { |n| fc_pq.push(n.to_s, rand) } }
157
+ bm.report('pq:pop') { N.times { pq_pq.pop } }
158
+ bm.report('fc:pop') { N.times { fc_pq.pop } }
159
+ end
160
+ ```
161
+
162
+ Output (reformatted):
163
+
164
+ | | user| system| total| real |
165
+ |:--------|---------:|---------:|---------:|-----------:|
166
+ |pqueue:push | 25.240|41.660 | 66.900| ( 66.871391)|
167
+ |*fc:push* | *0.040* | *0.000* | *0.040*| *( 0.035270)*|
168
+ |pqueue:pop | 0.010 | 0.000 | 0.010| ( 0.018718)|
169
+ |*fc:pop* | *0.070* | *0.000* | *0.070*| *( 0.061138)*|
170
+
171
+ Summary: FastContainers::PriorityQueue (fc) are *1672.5 times faster* on pushes and *7 times slower* on pops.
172
+
173
+ ### Comparison with [PriorityQueue (0.1.2)](https://rubygems.org/gems/PriorityQueue) (5,000,000 push/pop)
174
+
175
+
176
+ ```ruby
177
+ require 'fc'
178
+ require 'priority_queue'
179
+ require 'benchmark'
180
+
181
+ N = 5_000_000
182
+ pq_pq = CPriorityQueue.new
183
+ fc_pq = FastContainers::PriorityQueue.new(:min)
184
+
185
+ Benchmark.bm do |bm|
186
+ bm.report('pq:push') { N.times { |n| pq_pq.push(n.to_s,rand) } }
187
+ bm.report('fc:push') { N.times { |n| fc_pq.push(n.to_s, rand) } }
188
+ bm.report('pq:pop') { N.times { pq_pq.delete_min } }
189
+ bm.report('fc:pop') { N.times { fc_pq.pop } }
190
+ end
191
+ ```
192
+
193
+ Output (reformatted):
194
+
195
+ | | user| system| total| real |
196
+ |:--------|---------:|---------:|---------:|-----------:|
197
+ |PriorityQueue:push | 10.020| 0.430| 10.45|( 10.665449)|
198
+ |*fc:push* | *2.110*| *0.170*| *2.28*|*( 2.452529)*|
199
+ |PriorityQueue:pop | 25.860| 0.070| 25.93|( 25.949438)|
200
+ |*fc:pop* | *5.690*| *0.000*| *5.69*|*( 5.688552)*|
201
+
202
+ Summary: FastContainers::PriorityQueue (fc) are *4.58 times faster* on pushes and *4.54 times faster* on pops.
203
+
204
+ ## Which is the best priority queue implementation for ruby?
205
+
206
+ As it usually happens, the answer is: it depends. The evidence reported above shows that if you are only interested in the speed of push and pop methods, then priority_queue_cxx is a very good candidate. Few other important factors may make other libraries be better suited for your needs. The most glaring one is that priority_queue_cxx implementation (i.e., ```FastContainers::PriorityQueue```) does not support changes of priorities<sup><a id="backref1" href="#notes">1</a></sup>. If your problem requires this feature, the best candidate appears to be [PriorityQueue (0.1.2)](https://rubygems.org/gems/PriorityQueue) library. Also, in making your choice, you may want to consider the fact that not all the presented libraries appear to be actively maintained (although, no one gave any problem at the time of the writing).
207
+
208
+ ## API
209
+
210
+ Here it follows a transcription of the RDoc documentation for the library. I'm adding it here because I'm having difficulties in instructing the 'gem' executable to generate the correct files on installation (everything works fine using rdoc from the command line though). Any suggestion about how to solve this problem is *very* welcome.
211
+
212
+ ### FastContainers::PriorityQueue
213
+
214
+ #### Public Class Methods
215
+
216
+ ##### new(queue_kind)
217
+
218
+ Create a new priority queue and returns it. queue_kind specifies whether to build a :min or a :max queue.
219
+
220
+ Example:
221
+
222
+ ```ruby
223
+ pq = FastContainers::PriorityQueue.new(:min)
224
+ ```
225
+
226
+ #### Public Instance Methods
227
+
228
+ ##### each { |obj,priority| ... } → self
229
+
230
+ Iterates through the priority queue yielding each element to the given block. The order of the yielded elements is not defined. Returns self.
231
+
232
+ Example:
233
+
234
+ ```ruby
235
+
236
+ pq.each do |obj,priority|
237
+ puts "Obj #{obj} has priority #{priority}"
238
+ end
239
+ ```
240
+
241
+ ##### next
242
+
243
+ Alias for: [top](#label-top+%E2%86%92+obj)
244
+
245
+ ##### next_key
246
+
247
+ Alias for: [top_key](#label-top_key+%E2%86%92+float)
248
+
249
+ #### second_best_key → float
250
+
251
+ Returns the priority of the second best element in the priority queue.
252
+
253
+ ##### empty?
254
+
255
+ Returns true if the queue is empty
256
+
257
+ ##### pop → self
258
+
259
+ Pops the top most element from the priority queue. Returns self.
260
+
261
+ ##### pop_each { |obj, priority| ... } → self
262
+
263
+ Iterates through the priority queue popping the top element and yielding it to the block. The order of yielded elements is guaranteed to be the priority order. Returns self.
264
+
265
+ Example:
266
+
267
+ ```ruby
268
+ ary = [100, 1, 90, 55, 6]
269
+ ary.each { |x| pq.push(x.to_s, x)}
270
+ ary.pop_each {|obj, priority| print(priority, ',') } # => 1,6,55,90,100,
271
+ ```
272
+
273
+ ##### push(obj,priority) → self
274
+
275
+ Push the obj/priority pair into the queue and returns self.
276
+
277
+ ##### size → num
278
+
279
+ Returns the size of the priority queue
280
+
281
+ ##### top → obj
282
+
283
+ Returns the object at the top of the priority queue.
284
+
285
+ ##### top_key → float
286
+
287
+ Returns the priority of the object at the top of the priority queue.
288
+
289
+ #### Included Modules
290
+
291
+ The class Includes Enumerable, so that standard enumeration based methods (e.g., map, all?, any?, ...) can all be used with this container. Notice that Enumerable methods are based on #each, implying that the order used to iterate through the container is undefined.
292
+
293
+ ## Notes
294
+
295
+ <sup id="ref1">1</sup> It is worth mentioning that, due to how priority queue are implemented by the C++ standard library, this implementation can't efficiently support priority changes. In any case, to support this feature would require important changes in the current API.<a href="#which-is-the-best-priority-queue-implementation-for-ruby" title="back reference">&#8617;</a>
@@ -0,0 +1,272 @@
1
+ // Copyright (c) 2014 Roberto Esposito
2
+ //
3
+ // Permission is hereby granted, free of charge, to any person obtaining
4
+ // a copy of this software and associated documentation files (the
5
+ // "Software"), to deal in the Software without restriction, including
6
+ // without limitation the rights to use, copy, modify, merge, publish,
7
+ // distribute, sublicense, and/or sell copies of the Software, and to
8
+ // permit persons to whom the Software is furnished to do so, subject to
9
+ // the following conditions:
10
+ //
11
+ // The above copyright notice and this permission notice shall be
12
+ // included in all copies or substantial portions of the Software.
13
+ //
14
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+ #include "ruby.h"
22
+ #include "fc_pq.h"
23
+
24
+ // Defining a space for information and references about the module to be stored internally
25
+ static VALUE FastContainers = Qnil;
26
+ static VALUE PriorityQueue = Qnil;
27
+
28
+ // --------------------------------------------------------------------------------
29
+ // UTILITIES
30
+ // --------------------------------------------------------------------------------
31
+
32
+ static fc_pq::PQueue pq_from_self(VALUE self) {
33
+ fc_pq::PQueue queue;
34
+ Data_Get_Struct(self, struct fc_pq::_PQueue, queue);
35
+
36
+ return queue;
37
+ }
38
+
39
+ static void pq_mark(void *ptr) {
40
+ if(ptr==NULL)
41
+ return;
42
+
43
+ fc_pq::PQueueIterator it = fc_pq::iterator((fc_pq::PQueue)ptr);
44
+ while( !fc_pq::iterator_end(it) ) {
45
+ rb_gc_mark( (VALUE) fc_pq::iterator_get_value(it) );
46
+ it = fc_pq::iterator_next(it);
47
+ }
48
+ fc_pq::iterator_dispose(it);
49
+ }
50
+
51
+ // --------------------------------------------------------------------------------
52
+ // METHODS
53
+ // --------------------------------------------------------------------------------
54
+
55
+ /*
56
+ * call-seq:
57
+ * PriorityQueue.new(queue_kind)
58
+ *
59
+ * Create a new priority queue and returns it.
60
+ * +queue_kind+ specifies whether to build a :min or a :max queue.
61
+ */
62
+ static VALUE pq_new(VALUE klass, VALUE queue_kind) {
63
+ if( TYPE(queue_kind) != T_SYMBOL ) {
64
+ rb_raise(rb_eTypeError, "queue_kind parameter must be a symbol");
65
+ }
66
+
67
+ fc_pq::PQueueKind kind;
68
+
69
+ if( rb_intern("max") == rb_to_id(queue_kind) )
70
+ kind = fc_pq::MAX_QUEUE;
71
+ else if( rb_intern("min") == rb_to_id(queue_kind) )
72
+ kind = fc_pq::MIN_QUEUE;
73
+ else rb_raise(rb_eTypeError, "queue_kind parameter must be either :max or :min");
74
+
75
+ fc_pq::PQueue queue = fc_pq::create(kind);
76
+ VALUE data = Data_Wrap_Struct(klass, pq_mark, fc_pq::destroy, queue);
77
+ rb_obj_call_init(data, 0, NULL);
78
+ return data;
79
+ }
80
+
81
+ /*
82
+ * call-seq:
83
+ * size -> num
84
+ *
85
+ * Returns the size of the priority queue
86
+ */
87
+
88
+ static VALUE pq_size(VALUE self) {
89
+ return INT2NUM(fc_pq::size(pq_from_self(self)));
90
+ }
91
+
92
+ /*
93
+ * call-seq:
94
+ * push(obj,priority) -> self
95
+ *
96
+ * Push the +obj+/+priority+ pair into the queue and returns self.
97
+ */
98
+ static VALUE pq_push(VALUE self, VALUE obj, VALUE priority) {
99
+ fc_pq::push(pq_from_self(self), (void*)obj, NUM2DBL(priority));
100
+ return self;
101
+ }
102
+
103
+ /*
104
+ * call-seq:
105
+ * top -> obj
106
+ *
107
+ * Returns the object at the top of the priority queue.
108
+ */
109
+ static VALUE pq_top(VALUE self) {
110
+ fc_pq::PQueue queue = pq_from_self(self);
111
+ if( fc_pq::empty(queue) ) {
112
+ return Qnil;
113
+ }
114
+
115
+ return (VALUE) fc_pq::top( queue );
116
+ }
117
+
118
+ /*
119
+ * call-seq:
120
+ * top_key -> float
121
+ *
122
+ * Returns the priority of the object at the top of the priority queue.
123
+ */
124
+ static VALUE pq_top_key(VALUE self) {
125
+ fc_pq::PQueue queue = pq_from_self(self);
126
+ if(fc_pq::empty(queue))
127
+ return Qnil;
128
+
129
+ double priority = fc_pq::top_key(queue);
130
+ return DBL2NUM(priority);
131
+ }
132
+
133
+ /*
134
+ * call-seq:
135
+ * second_best_key -> float
136
+ *
137
+ * Returns the priority of the second best element in the priority queue.
138
+ */
139
+ static VALUE pq_second_best_key(VALUE self) {
140
+ fc_pq::PQueue queue = pq_from_self(self);
141
+ if(fc_pq::size(queue) < 2)
142
+ return Qnil;
143
+
144
+ double priority = fc_pq::second_best_key(queue);
145
+ return DBL2NUM(priority);
146
+ }
147
+
148
+ /*
149
+ * call-seq:
150
+ * pop -> obj
151
+ *
152
+ * Pops the top most element from the priority queue.
153
+ * Returns the top object (before the pop).
154
+ */
155
+ static VALUE pq_pop(VALUE self) {
156
+ fc_pq::PQueue queue = pq_from_self(self);
157
+
158
+ if( fc_pq::empty(queue) )
159
+ rb_raise(rb_eRuntimeError, "Pop called on an empty queue");
160
+
161
+ VALUE top = (VALUE) fc_pq::top( queue );
162
+ fc_pq::pop(queue);
163
+
164
+ return top;
165
+ }
166
+
167
+ /*
168
+ * call-seq:
169
+ * empty?
170
+ *
171
+ * Returns true if the queue is empty
172
+ */
173
+
174
+ static VALUE pq_empty(VALUE self) {
175
+ if( fc_pq::empty(pq_from_self(self)) )
176
+ return Qtrue;
177
+ else
178
+ return Qfalse;
179
+ }
180
+
181
+
182
+ /*
183
+ * call-seq:
184
+ * each { |obj,priority| ... } -> self
185
+ *
186
+ * Iterates through the priority queue yielding each element to the given block.
187
+ * The order of the yielded elements is not defined. The given block *must not* change
188
+ * the queue elements order. In case it does the iteration will be aborted and the
189
+ * method will return nil.
190
+ *
191
+ * Returns self.
192
+ */
193
+
194
+ static VALUE pq_each(VALUE self) {
195
+ fc_pq::PQueue queue = pq_from_self(self);
196
+ fc_pq::PQueueIterator iterator;
197
+
198
+ try {
199
+ iterator = fc_pq::iterator(queue);
200
+ while( !fc_pq::iterator_end(iterator) ) {
201
+ VALUE value = (VALUE) fc_pq::iterator_get_value(iterator);
202
+ VALUE num = DBL2NUM(fc_pq::iterator_get_key(iterator));
203
+ rb_yield_values( 2,value, num );
204
+ fc_pq::iterator_next(iterator);
205
+ }
206
+ fc_pq::iterator_dispose(iterator);
207
+ } catch (fc_pq::PQueueException& exception) {
208
+ fc_pq::iterator_dispose(iterator);
209
+ rb_raise(rb_eRuntimeError, "%s", exception.what());
210
+ return Qnil;
211
+ }
212
+
213
+ return self;
214
+ }
215
+
216
+ /*
217
+ * call-seq:
218
+ * pop_each { |obj, priority| ... } -> self
219
+ *
220
+ * Iterates through the priority queue popping the top element and
221
+ * yielding it to the block. The order of yielded elements is guaranteed
222
+ * to be the priority order.
223
+ * Returns self.
224
+ */
225
+
226
+ static VALUE pq_pop_each(VALUE self) {
227
+ fc_pq::PQueue queue= pq_from_self(self);
228
+ while( !fc_pq::empty(queue) ) {
229
+ VALUE value = (VALUE) fc_pq::top(queue);
230
+ double key = fc_pq::top_key(queue);
231
+ fc_pq::pop(queue);
232
+ rb_yield_values(2, value, DBL2NUM(key));
233
+ }
234
+
235
+ return self;
236
+ }
237
+
238
+ // --------------------------------------------------------------------------------
239
+ // INITIALIZATION
240
+ // --------------------------------------------------------------------------------
241
+
242
+ /*
243
+ * Document-module: FastContainers
244
+ * Exposes C++ implementation of some containers not defined in the standard ruby libraries.
245
+ */
246
+
247
+ /*
248
+ * Document-class: FastContainers::PriorityQueue
249
+ * Implements priority queues through a C++ heap (using the standard std::priority_queue class).
250
+ * Includes Enumerable, so that standard enumeration based methods (e.g., map, all?, any?, ...)
251
+ * can all be used with this container. Notice that Enumerable methods are based on #each, implying
252
+ * that the order used to iterate through the container is undefined.
253
+ */
254
+ extern "C" {
255
+ void Init_fast_containers() {
256
+ FastContainers = rb_define_module("FastContainers");
257
+ PriorityQueue = rb_define_class_under(FastContainers, "PriorityQueue", rb_cObject);
258
+ rb_global_variable(&FastContainers);
259
+ rb_global_variable(&PriorityQueue);
260
+
261
+ rb_define_singleton_method(PriorityQueue, "new", RUBY_METHOD_FUNC(pq_new), 1);
262
+ rb_define_method(PriorityQueue, "size", RUBY_METHOD_FUNC(pq_size), 0);
263
+ rb_define_method(PriorityQueue, "push", RUBY_METHOD_FUNC(pq_push), 2);
264
+ rb_define_method(PriorityQueue, "top", RUBY_METHOD_FUNC(pq_top), 0);
265
+ rb_define_method(PriorityQueue, "top_key", RUBY_METHOD_FUNC(pq_top_key), 0);
266
+ rb_define_method(PriorityQueue, "second_best_key", RUBY_METHOD_FUNC(pq_second_best_key), 0);
267
+ rb_define_method(PriorityQueue, "pop", RUBY_METHOD_FUNC(pq_pop), 0);
268
+ rb_define_method(PriorityQueue, "empty?", RUBY_METHOD_FUNC(pq_empty), 0);
269
+ rb_define_method(PriorityQueue, "each", RUBY_METHOD_FUNC(pq_each), 0);
270
+ rb_define_method(PriorityQueue, "pop_each", RUBY_METHOD_FUNC(pq_pop_each), 0);
271
+ }
272
+ }