priority_queue_cxx 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +294 -0
- data/ext/fast_containers/FastContainers.cpp +272 -0
- data/ext/fast_containers/extconf.rb +5 -0
- data/ext/fast_containers/fc_pq.cpp +158 -0
- data/ext/fast_containers/fc_pq.h +85 -0
- data/lib/fc.rb +32 -0
- data/test/performance/test_fc_vs_algorithms.rb +37 -0
- data/test/performance/test_fc_vs_cpriority_queue.rb +37 -0
- data/test/performance/test_fc_vs_em_priority_queue.rb +37 -0
- data/test/performance/test_fc_vs_pqueue.rb +37 -0
- data/test/performance/test_fc_vs_priority_queue.rb +37 -0
- data/test/test_fast_containers.rb +245 -0
- metadata +75 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c2b5bbef541a1b74a11e959cda5b1b11020bda89
|
4
|
+
data.tar.gz: 15d62c6289e5d07cacafba804497305b6719c532
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7f14a5601f02ab38049968a222dd01d9403755984f0b91f6365b881cfe5af229173edf16290aa7568e15a87fd343205d965c9f8f2782cf096aed070cbd3ad934
|
7
|
+
data.tar.gz: 264b327c4dbc023d21a06868eebe55b76812d6f48b3a9797dd456aeb206766c936fd00ea1d1ae97ac3e58ae70a04a0b891b866ac14da513ae152f52b1ba3015f
|
data/README.md
ADDED
@@ -0,0 +1,294 @@
|
|
1
|
+
# PriorityQueueCxx
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/fast_containers.png)](http://badge.fury.io/rb/fast_containers)
|
4
|
+
|
5
|
+
FastContainers provides a fast implementatin 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 a number of containers that are not in the standard ruby library and are presently only available as pure ruby libraries, but presently the library includes a single class named PriorityQueue. More containers will be added as necessity arises. Contributors and feature requests are most welcome.
|
6
|
+
|
7
|
+
The library exposes a module named 'FastContainers' (to be required using ```require 'fc'```) which provides the PriorityQueue class.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem install 'priority_queue_cxx'
|
13
|
+
```
|
14
|
+
|
15
|
+
## Usage Example
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
|
19
|
+
require 'fc'
|
20
|
+
q = FastContainers::PriorityQueue.new(:max)
|
21
|
+
q.push("largest", 10)
|
22
|
+
q.push("smallest", 5)
|
23
|
+
q.top # => "largest"
|
24
|
+
q.top_key # => 10
|
25
|
+
q.pop
|
26
|
+
```
|
27
|
+
|
28
|
+
## How fast is it?
|
29
|
+
|
30
|
+
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.
|
31
|
+
|
32
|
+
To get an idea about how fast it is, below we 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 others 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.
|
33
|
+
|
34
|
+
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.
|
35
|
+
|
36
|
+
| library | avg μs per push | avg μs per pop | avg μs per op |
|
37
|
+
|:--------|---------:|---------:|---------:|
|
38
|
+
| *priority_queue_cxx* | *0.456* | *1.138* | *0.797* |
|
39
|
+
| PriorityQueue | 2.09 | 5.186 | 3.638 |
|
40
|
+
| em-priority-queue | 3.56 | 8.32 | 5.94 |
|
41
|
+
| pqueue | 669.0 | 0.1 | 334.55|
|
42
|
+
| algorithms | 2584.6 | 29.6 |1307.1 |
|
43
|
+
| priority_queue | 1.4 |19134.6 |9568.0 |
|
44
|
+
|
45
|
+
where: results are sorted according to "avg μs per op" (higher 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).
|
46
|
+
|
47
|
+
|
48
|
+
### Comparison with [algorithms (0.6.1)](http://rubygems.org/gems/algorithms) (50,000 push/pop)
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
|
52
|
+
require 'fc'
|
53
|
+
require 'algorithms'
|
54
|
+
require 'benchmark'
|
55
|
+
|
56
|
+
N = 50_000
|
57
|
+
algo_pq = Containers::PriorityQueue.new
|
58
|
+
fc_pq = FastContainers::PriorityQueue.new(:min)
|
59
|
+
|
60
|
+
Benchmark.bm do |bm|
|
61
|
+
bm.report('algo:push') { N.times { |n| algo_pq.push(n.to_s, rand) } }
|
62
|
+
bm.report('fc:push') { N.times { |n| fc_pq.push(n.to_s, rand) } }
|
63
|
+
bm.report('algo:pop') { N.times { algo_pq.pop } }
|
64
|
+
bm.report('fc:pop') { N.times { fc_pq.pop } }
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
Output (reformatted):
|
69
|
+
|
70
|
+
| | user| system| total| real |
|
71
|
+
|:--------|---------:|---------:|---------:|-----------:|
|
72
|
+
|algorithms:push|122.200| 7.030|129.230|(129.173)|
|
73
|
+
|*fc:push* | *0.020*| *0.000*| *0.020*|*( 0.020)*|
|
74
|
+
|algorithms:pop | 1.460| 0.020| 1.480|( 1.476)|
|
75
|
+
|*fc:pop* | *0.030*| *0.000*| *0.030*|*( 0.030)*|
|
76
|
+
|
77
|
+
Summary: FastContainers::PriorityQueues (fc) are *6461.5 times faster* on pushes and *49.3 times faster* on pops.
|
78
|
+
|
79
|
+
|
80
|
+
### Comparison with [priority_queue (0.2.0)](http://rubygems.org/gems/priority_queue) (50,000 push/pop)
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
require 'fc'
|
84
|
+
require 'priority_queue'
|
85
|
+
require 'benchmark'
|
86
|
+
|
87
|
+
N = 50_000
|
88
|
+
pq_pq = PriorityQueue.new
|
89
|
+
fc_pq = FastContainers::PriorityQueue.new(:min)
|
90
|
+
|
91
|
+
Benchmark.bm do |bm|
|
92
|
+
bm.report('pq:push') { N.times { |n| pq_pq[rand] << n.to_s } }
|
93
|
+
bm.report('fc:push') { N.times { |n| fc_pq.push(n.to_s, rand) } }
|
94
|
+
bm.report('pq:pop') { N.times { pq_pq.shift } }
|
95
|
+
bm.report('fc:pop') { N.times { fc_pq.pop } }
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
Output (reformatted):
|
100
|
+
|
101
|
+
| | user| system| total| real |
|
102
|
+
|:--------|---------:|---------:|---------:|-----------:|
|
103
|
+
|priority_queue:push | 0.060 | 0.010 | 0.070 |( 0.062593)|
|
104
|
+
|*fc:push* | *0.020* | *0.000* | *0.020* |*( 0.018866)*|
|
105
|
+
|priority_queue:pop | 948.440 | 8.290 | 956.730 |(956.676601)|
|
106
|
+
|*fc:pop* | 0.040 | 0.000 | 0.040 |*( 0.032753)*|
|
107
|
+
|
108
|
+
Summary: FastContainers::PriorityQueues (fc) are *3.5 times faster* on pushes and *23918.25 times faster* on pops.
|
109
|
+
|
110
|
+
### Comparison with [em-priority-queue (1.1.2)](http://rubygems.org/gems/em-priority-queue) (500,000 push/pop)
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
require 'fc'
|
114
|
+
require 'em-priority-queue'
|
115
|
+
require 'benchmark'
|
116
|
+
|
117
|
+
N = 500_000
|
118
|
+
em_pq = EM::PriorityQueue.new
|
119
|
+
fc_pq = FastContainers::PriorityQueue.new(:min)
|
120
|
+
|
121
|
+
Benchmark.bm do |bm|
|
122
|
+
bm.report('em:push') { N.times { |n| em_pq.push(n.to_s, rand) } }
|
123
|
+
bm.report('fc:push') { N.times { |n| fc_pq.push(n.to_s, rand) } }
|
124
|
+
bm.report('em:pop') { N.times { em_pq.pop {} } }
|
125
|
+
bm.report('fc:pop') { N.times { fc_pq.pop } }
|
126
|
+
end
|
127
|
+
```
|
128
|
+
|
129
|
+
Output (reformatted):
|
130
|
+
|
131
|
+
| | user| system| total| real |
|
132
|
+
|:--------|---------:|---------:|---------:|-----------:|
|
133
|
+
|em-priority-queue:push |1.650 |0.130 | 1.780 | ( 1.895794) |
|
134
|
+
|*fc:push* |*0.190* |*0.020* | *0.210* | *( 0.224068)* |
|
135
|
+
|em-priority-queue:pop |3.980 |0.180 | 4.160 | ( 4.360084) |
|
136
|
+
|*fc:pop* |*0.380* |*0.000* | *0.380* | *( 0.381250)* |
|
137
|
+
|
138
|
+
Summary: FastContainers::PriorityQueue (fc) are *8.5 times faster* on pushes and *10.9 times faster* on pops.
|
139
|
+
|
140
|
+
### Comparison with [pqueue (2.0.2)](http://rubygems.org/gems/pqueue) (100,000 push/pop)
|
141
|
+
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
require 'fc'
|
145
|
+
require 'pqueue'
|
146
|
+
require 'benchmark'
|
147
|
+
|
148
|
+
N = 100_000
|
149
|
+
pq_pq = PQueue.new { |x,y| x[1] <=> y[1] }
|
150
|
+
fc_pq = FastContainers::PriorityQueue.new(:min)
|
151
|
+
|
152
|
+
Benchmark.bm do |bm|
|
153
|
+
bm.report('pq:push') { N.times { |n| pq_pq.push([n,rand]) } }
|
154
|
+
bm.report('fc:push') { N.times { |n| fc_pq.push(n.to_s, rand) } }
|
155
|
+
bm.report('pq:pop') { N.times { pq_pq.pop } }
|
156
|
+
bm.report('fc:pop') { N.times { fc_pq.pop } }
|
157
|
+
end
|
158
|
+
```
|
159
|
+
|
160
|
+
Output (reformatted):
|
161
|
+
|
162
|
+
| | user| system| total| real |
|
163
|
+
|:--------|---------:|---------:|---------:|-----------:|
|
164
|
+
|pqueue:push | 25.240|41.660 | 66.900| ( 66.871391)|
|
165
|
+
|*fc:push* | *0.040* | *0.000* | *0.040*| *( 0.035270)*|
|
166
|
+
|pqueue:pop | 0.010 | 0.000 | 0.010| ( 0.018718)|
|
167
|
+
|*fc:pop* | *0.070* | *0.000* | *0.070*| *( 0.061138)*|
|
168
|
+
|
169
|
+
Summary: FastContainers::PriorityQueue (fc) are *1672.5 times faster* on pushes and *7 times slower* on pops.
|
170
|
+
|
171
|
+
### Comparison with [PriorityQueue (0.1.2)](https://rubygems.org/gems/PriorityQueue) (5,000,000 push/pop)
|
172
|
+
|
173
|
+
|
174
|
+
```ruby
|
175
|
+
require 'fc'
|
176
|
+
require 'priority_queue'
|
177
|
+
require 'benchmark'
|
178
|
+
|
179
|
+
N = 5_000_000
|
180
|
+
pq_pq = CPriorityQueue.new
|
181
|
+
fc_pq = FastContainers::PriorityQueue.new(:min)
|
182
|
+
|
183
|
+
Benchmark.bm do |bm|
|
184
|
+
bm.report('pq:push') { N.times { |n| pq_pq.push(n.to_s,rand) } }
|
185
|
+
bm.report('fc:push') { N.times { |n| fc_pq.push(n.to_s, rand) } }
|
186
|
+
bm.report('pq:pop') { N.times { pq_pq.delete_min } }
|
187
|
+
bm.report('fc:pop') { N.times { fc_pq.pop } }
|
188
|
+
end
|
189
|
+
```
|
190
|
+
|
191
|
+
Output (reformatted):
|
192
|
+
|
193
|
+
| | user| system| total| real |
|
194
|
+
|:--------|---------:|---------:|---------:|-----------:|
|
195
|
+
|PriorityQueue:push | 10.020| 0.430| 10.45|( 10.665449)|
|
196
|
+
|*fc:push* | *2.110*| *0.170*| *2.28*|*( 2.452529)*|
|
197
|
+
|PriorityQueue:pop | 25.860| 0.070| 25.93|( 25.949438)|
|
198
|
+
|*fc:pop* | *5.690*| *0.000*| *5.69*|*( 5.688552)*|
|
199
|
+
|
200
|
+
Summary: FastContainers::PriorityQueue (fc) are *4.58 times faster* on pushes and *4.54 times faster* on pops.
|
201
|
+
|
202
|
+
## Which is the best priority queue implementation for ruby?
|
203
|
+
|
204
|
+
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).
|
205
|
+
|
206
|
+
## API
|
207
|
+
|
208
|
+
Here it follows a transcription of the RDoc documentation for the library. I'm adding it here because I've 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.
|
209
|
+
|
210
|
+
### FastContainers::PriorityQueue
|
211
|
+
|
212
|
+
#### Public Class Methods
|
213
|
+
|
214
|
+
##### new(queue_kind)
|
215
|
+
|
216
|
+
Create a new priority queue and returns it. queue_kind specifies whether to build a :min or a :max queue.
|
217
|
+
|
218
|
+
Example:
|
219
|
+
|
220
|
+
```ruby
|
221
|
+
pq = FastContainers::PriorityQueue.new(:min)
|
222
|
+
```
|
223
|
+
|
224
|
+
#### Public Instance Methods
|
225
|
+
|
226
|
+
##### each { |obj,priority| ... } → self
|
227
|
+
|
228
|
+
Iterates through the priority queue yielding each element to the given block. The order of the yielded elements is not defined. Returns self.
|
229
|
+
|
230
|
+
Example:
|
231
|
+
|
232
|
+
```ruby
|
233
|
+
|
234
|
+
pq.each do |obj,priority|
|
235
|
+
puts "Obj #{obj} has priority #{priority}"
|
236
|
+
end
|
237
|
+
```
|
238
|
+
|
239
|
+
##### next
|
240
|
+
|
241
|
+
Alias for: [top](#label-top+%E2%86%92+obj)
|
242
|
+
|
243
|
+
##### next_key
|
244
|
+
|
245
|
+
Alias for: [top_key](#label-top_key+%E2%86%92+float)
|
246
|
+
|
247
|
+
#### second_best_key → float
|
248
|
+
|
249
|
+
Returns the priority of the second best element in the priority queue.
|
250
|
+
|
251
|
+
##### empty?
|
252
|
+
|
253
|
+
Returns true if the queue is empty
|
254
|
+
|
255
|
+
##### pop → self
|
256
|
+
|
257
|
+
Pops the top most element from the priority queue. Returns self.
|
258
|
+
|
259
|
+
##### pop_each { |obj, priority| ... } → self
|
260
|
+
|
261
|
+
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.
|
262
|
+
|
263
|
+
Example:
|
264
|
+
|
265
|
+
```ruby
|
266
|
+
ary = [100, 1, 90, 55, 6]
|
267
|
+
ary.each { |x| pq.push(x.to_s, x)}
|
268
|
+
ary.pop_each {|obj, priority| print(priority, ',') } # => 1,6,55,90,100,
|
269
|
+
```
|
270
|
+
|
271
|
+
##### push(obj,priority) → self
|
272
|
+
|
273
|
+
Push the obj/priority pair into the queue and returns self.
|
274
|
+
|
275
|
+
##### size → num
|
276
|
+
|
277
|
+
Returns the size of the priority queue
|
278
|
+
|
279
|
+
##### top → obj
|
280
|
+
|
281
|
+
Returns the object at the top of the priority queue.
|
282
|
+
|
283
|
+
##### top_key → float
|
284
|
+
|
285
|
+
Returns the priority of the object at the top of the priority queue.
|
286
|
+
|
287
|
+
#### Included Modules
|
288
|
+
|
289
|
+
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.
|
290
|
+
|
291
|
+
## Notes
|
292
|
+
|
293
|
+
<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">↩</a>
|
294
|
+
|
@@ -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
|
+
}
|
@@ -0,0 +1,158 @@
|
|
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 "fc_pq.h"
|
22
|
+
#include <iostream>
|
23
|
+
|
24
|
+
namespace fc_pq {
|
25
|
+
|
26
|
+
typedef std::pair<void*,double> PQElem;
|
27
|
+
|
28
|
+
class PairsComparator
|
29
|
+
{
|
30
|
+
bool reverse;
|
31
|
+
public:
|
32
|
+
PairsComparator(PQueueKind kind) {reverse=(kind==MIN_QUEUE);}
|
33
|
+
bool operator() (const PQElem& lhs, const PQElem& rhs) const
|
34
|
+
{
|
35
|
+
if (reverse) return (lhs.second>rhs.second);
|
36
|
+
else return (lhs.second<rhs.second);
|
37
|
+
}
|
38
|
+
};
|
39
|
+
|
40
|
+
// --------------------------------------
|
41
|
+
// PQueue
|
42
|
+
// --------------------------------------
|
43
|
+
|
44
|
+
typedef std::vector<PQElem> PQueueStorage;
|
45
|
+
typedef unsigned int PQueueStorageVersion;
|
46
|
+
|
47
|
+
typedef struct _PQueue {
|
48
|
+
PQueueStorage storage;
|
49
|
+
PairsComparator comparator;
|
50
|
+
PQueueStorageVersion version;
|
51
|
+
|
52
|
+
_PQueue(PQueueKind kind) : comparator(kind), version(0) { }
|
53
|
+
}* PQueue;
|
54
|
+
|
55
|
+
void destroy(PQueue q){
|
56
|
+
delete q;
|
57
|
+
}
|
58
|
+
|
59
|
+
PQueue create(PQueueKind kind) {
|
60
|
+
return new _PQueue(kind);
|
61
|
+
}
|
62
|
+
|
63
|
+
/* Getting the size of the container */
|
64
|
+
unsigned int size(PQueue q) {
|
65
|
+
return q->storage.size();
|
66
|
+
}
|
67
|
+
|
68
|
+
|
69
|
+
void push(PQueue q, void* value, double priority) {
|
70
|
+
q->version++;
|
71
|
+
q->storage.push_back(PQElem(value, priority));
|
72
|
+
push_heap(q->storage.begin(), q->storage.end(), q->comparator);
|
73
|
+
}
|
74
|
+
|
75
|
+
void* top(PQueue q) {
|
76
|
+
return q->storage.at(0).first;
|
77
|
+
}
|
78
|
+
|
79
|
+
double top_key(PQueue q) {
|
80
|
+
return q->storage.at(0).second;
|
81
|
+
}
|
82
|
+
|
83
|
+
double second_best_key(PQueue q) {
|
84
|
+
if(q->storage.size()==2)
|
85
|
+
return q->storage.at(1).second;
|
86
|
+
|
87
|
+
double key1 = q->storage.at(1).second;
|
88
|
+
double key2 = q->storage.at(2).second;
|
89
|
+
if( key1 > key2 ) {
|
90
|
+
return key1;
|
91
|
+
} else {
|
92
|
+
return key2;
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
void pop(PQueue q) {
|
97
|
+
q->version++;
|
98
|
+
pop_heap(q->storage.begin(), q->storage.end(), q->comparator);
|
99
|
+
q->storage.pop_back();
|
100
|
+
}
|
101
|
+
|
102
|
+
bool empty(PQueue q) {
|
103
|
+
return q->storage.empty();
|
104
|
+
}
|
105
|
+
|
106
|
+
// --------------------------------------
|
107
|
+
// Iterator
|
108
|
+
// --------------------------------------
|
109
|
+
|
110
|
+
|
111
|
+
typedef struct _PQueueIterator {
|
112
|
+
PQueueStorage::const_iterator iterator;
|
113
|
+
PQueue pqueue;
|
114
|
+
PQueueStorage* storage;
|
115
|
+
PQueueStorageVersion version;
|
116
|
+
|
117
|
+
_PQueueIterator(PQueue q) : iterator(q->storage.begin()), pqueue(q), storage(&q->storage), version(q->version)
|
118
|
+
{ }
|
119
|
+
|
120
|
+
void checkVersion() throw(PQueueException) {
|
121
|
+
if(version != pqueue->version) {
|
122
|
+
throw PQueueException("FastContainers::PriorityQueue - a change in the priority queue invalidated the current iterator.");
|
123
|
+
}
|
124
|
+
}
|
125
|
+
} PQueueImplIterator;
|
126
|
+
#define QIT(it) ((PQueueImplIterator*)(it))
|
127
|
+
|
128
|
+
/* Returns a new iterator object */
|
129
|
+
PQueueIterator iterator(PQueue q) {
|
130
|
+
PQueueImplIterator* it = new PQueueImplIterator(q);
|
131
|
+
return it;
|
132
|
+
}
|
133
|
+
|
134
|
+
void iterator_dispose(PQueueIterator it) {
|
135
|
+
delete it;
|
136
|
+
}
|
137
|
+
|
138
|
+
/* Returns the value of the current element */
|
139
|
+
void* iterator_get_value(PQueueIterator it) {
|
140
|
+
return it->iterator->first;
|
141
|
+
}
|
142
|
+
|
143
|
+
/* Returns the priority of the current element */
|
144
|
+
double iterator_get_key(PQueueIterator it) {
|
145
|
+
return it->iterator->second;
|
146
|
+
}
|
147
|
+
|
148
|
+
/* Moves on to the next element */
|
149
|
+
PQueueIterator iterator_next(PQueueIterator it) throw(PQueueException) {
|
150
|
+
it->checkVersion();
|
151
|
+
it->iterator++;
|
152
|
+
return it;
|
153
|
+
}
|
154
|
+
|
155
|
+
bool iterator_end(PQueueIterator it) {
|
156
|
+
return it->iterator == it->storage->end();
|
157
|
+
}
|
158
|
+
}
|
@@ -0,0 +1,85 @@
|
|
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
|
+
#ifndef FC_QUEUE_H_KTY6FH1S
|
22
|
+
#define FC_QUEUE_H_KTY6FH1S
|
23
|
+
|
24
|
+
#include <queue>
|
25
|
+
|
26
|
+
namespace fc_pq {
|
27
|
+
class PQueueException : public std::runtime_error {
|
28
|
+
public:
|
29
|
+
PQueueException(const char* msg) : std::runtime_error(msg) {}
|
30
|
+
};
|
31
|
+
|
32
|
+
typedef struct _PQueue* PQueue;
|
33
|
+
typedef struct _PQueueIterator* PQueueIterator;
|
34
|
+
typedef enum { MIN_QUEUE, MAX_QUEUE } PQueueKind;
|
35
|
+
|
36
|
+
/* Constructor. It defaults to construct a max queue. If true is passed
|
37
|
+
it construct a min queue.*/
|
38
|
+
PQueue create(PQueueKind kind);
|
39
|
+
|
40
|
+
/* Destructor */
|
41
|
+
void destroy(PQueue q);
|
42
|
+
|
43
|
+
/* Getting the size of the container */
|
44
|
+
unsigned int size(PQueue q);
|
45
|
+
|
46
|
+
/* Adding elements */
|
47
|
+
void push(PQueue q, void* value, double priority);
|
48
|
+
|
49
|
+
/* Inspecting the queue top (for values) */
|
50
|
+
void* top(PQueue q);
|
51
|
+
|
52
|
+
/* Inspecting the queue top (for priorities) */
|
53
|
+
double top_key(PQueue q);
|
54
|
+
|
55
|
+
/* Returns the priority of the next best element */
|
56
|
+
double second_best_key(PQueue q);
|
57
|
+
|
58
|
+
/* Removing the queue top */
|
59
|
+
void pop(PQueue q);
|
60
|
+
|
61
|
+
/* Returns true if the queue is empty */
|
62
|
+
bool empty(PQueue q);
|
63
|
+
|
64
|
+
/* Returns a new iterator object */
|
65
|
+
PQueueIterator iterator(PQueue q);
|
66
|
+
|
67
|
+
/* Dispose the iterator */
|
68
|
+
void iterator_dispose(PQueueIterator it);
|
69
|
+
|
70
|
+
/* Returns the value of the current element */
|
71
|
+
void* iterator_get_value(PQueueIterator it);
|
72
|
+
|
73
|
+
/* Returns the priority of the current element */
|
74
|
+
double iterator_get_key(PQueueIterator it);
|
75
|
+
|
76
|
+
/* Moves on to the next element */
|
77
|
+
PQueueIterator iterator_next(PQueueIterator it) throw(PQueueException);
|
78
|
+
|
79
|
+
/* Return true if the iterator is already out of the container */
|
80
|
+
bool iterator_end(PQueueIterator it);
|
81
|
+
}
|
82
|
+
|
83
|
+
#endif /* end of include guard: FC_QUEUE_H_KTY6FH1S */
|
84
|
+
|
85
|
+
|
data/lib/fc.rb
ADDED
@@ -0,0 +1,32 @@
|
|
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
|
+
require 'fast_containers'
|
22
|
+
|
23
|
+
module FastContainers
|
24
|
+
VERSION = "0.3.2"
|
25
|
+
|
26
|
+
class PriorityQueue
|
27
|
+
include Enumerable
|
28
|
+
|
29
|
+
alias_method :next, :top
|
30
|
+
alias_method :next_key, :top_key
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,37 @@
|
|
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
|
+
require 'fc'
|
22
|
+
require 'algorithms'
|
23
|
+
require 'benchmark'
|
24
|
+
|
25
|
+
# Performs 50.000 pushes and pops in priority queues using the fc and
|
26
|
+
# algorithms implementations and reports the time spent.
|
27
|
+
|
28
|
+
N = 50_000
|
29
|
+
algo_pq = Containers::PriorityQueue.new
|
30
|
+
fc_pq = FastContainers::PriorityQueue.new(:min)
|
31
|
+
|
32
|
+
Benchmark.bm do |bm|
|
33
|
+
bm.report('algo:push') { N.times { |n| algo_pq.push(n.to_s, rand) } }
|
34
|
+
bm.report('fc:push') { N.times { |n| fc_pq.push(n.to_s, rand) } }
|
35
|
+
bm.report('algo:pop') { N.times { algo_pq.pop } }
|
36
|
+
bm.report('fc:pop') { N.times { fc_pq.pop } }
|
37
|
+
end
|
@@ -0,0 +1,37 @@
|
|
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
|
+
require 'fc'
|
22
|
+
require 'priority_queue'
|
23
|
+
require 'benchmark'
|
24
|
+
|
25
|
+
# Performs 5,000,000 pushes and pops in priority queues using the fc and
|
26
|
+
# algorithms implementations and reports the time spent.
|
27
|
+
|
28
|
+
N = 5_000_000
|
29
|
+
pq_pq = CPriorityQueue.new
|
30
|
+
fc_pq = FastContainers::PriorityQueue.new(:min)
|
31
|
+
|
32
|
+
Benchmark.bm do |bm|
|
33
|
+
bm.report('pq:push') { N.times { |n| pq_pq.push(n.to_s,rand) } }
|
34
|
+
bm.report('fc:push') { N.times { |n| fc_pq.push(n.to_s, rand) } }
|
35
|
+
bm.report('pq:pop') { N.times { pq_pq.delete_min } }
|
36
|
+
bm.report('fc:pop') { N.times { fc_pq.pop } }
|
37
|
+
end
|
@@ -0,0 +1,37 @@
|
|
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
|
+
require 'fc'
|
22
|
+
require 'em-priority-queue'
|
23
|
+
require 'benchmark'
|
24
|
+
|
25
|
+
# Performs 50.000 pushes and pops in priority queues using the fc and
|
26
|
+
# algorithms implementations and reports the time spent.
|
27
|
+
|
28
|
+
N = 500_000
|
29
|
+
em_pq = EM::PriorityQueue.new
|
30
|
+
fc_pq = FastContainers::PriorityQueue.new(:min)
|
31
|
+
|
32
|
+
Benchmark.bm do |bm|
|
33
|
+
bm.report('em:push') { N.times { |n| em_pq.push(n.to_s, rand) } }
|
34
|
+
bm.report('fc:push') { N.times { |n| fc_pq.push(n.to_s, rand) } }
|
35
|
+
bm.report('em:pop') { N.times { em_pq.pop {} } }
|
36
|
+
bm.report('fc:pop') { N.times { fc_pq.pop } }
|
37
|
+
end
|
@@ -0,0 +1,37 @@
|
|
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
|
+
require 'fc'
|
22
|
+
require 'pqueue'
|
23
|
+
require 'benchmark'
|
24
|
+
|
25
|
+
# Performs 50.000 pushes and pops in priority queues using the fc and
|
26
|
+
# algorithms implementations and reports the time spent.
|
27
|
+
|
28
|
+
N = 100_000
|
29
|
+
pq_pq = PQueue.new { |x,y| x[1] <=> y[1] }
|
30
|
+
fc_pq = FastContainers::PriorityQueue.new(:min)
|
31
|
+
|
32
|
+
Benchmark.bm do |bm|
|
33
|
+
bm.report('pq:push') { N.times { |n| pq_pq.push([n,rand]) } }
|
34
|
+
bm.report('fc:push') { N.times { |n| fc_pq.push(n.to_s, rand) } }
|
35
|
+
bm.report('pq:pop') { N.times { pq_pq.pop } }
|
36
|
+
bm.report('fc:pop') { N.times { fc_pq.pop } }
|
37
|
+
end
|
@@ -0,0 +1,37 @@
|
|
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
|
+
require 'fc'
|
22
|
+
require 'priority_queue'
|
23
|
+
require 'benchmark'
|
24
|
+
|
25
|
+
# Performs 50.000 pushes and pops in priority queues using the fc and
|
26
|
+
# algorithms implementations and reports the time spent.
|
27
|
+
|
28
|
+
N = 50_000
|
29
|
+
pq_pq = PriorityQueue.new
|
30
|
+
fc_pq = FastContainers::PriorityQueue.new(:min)
|
31
|
+
|
32
|
+
Benchmark.bm do |bm|
|
33
|
+
bm.report('pq:push') { N.times { |n| pq_pq[rand] << n.to_s } }
|
34
|
+
bm.report('fc:push') { N.times { |n| fc_pq.push(n.to_s, rand) } }
|
35
|
+
bm.report('pq:pop') { N.times { pq_pq.shift } }
|
36
|
+
bm.report('fc:pop') { N.times { fc_pq.pop } }
|
37
|
+
end
|
@@ -0,0 +1,245 @@
|
|
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
|
+
require "minitest/autorun"
|
22
|
+
require "fc"
|
23
|
+
|
24
|
+
class TestFastContainers < MiniTest::Unit::TestCase
|
25
|
+
def test_new_object_creation
|
26
|
+
assert !FastContainers::PriorityQueue.new(:max).nil?
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_new_handling_of_bad_parameter
|
30
|
+
assert_raises(TypeError) do
|
31
|
+
FastContainers::PriorityQueue.new(true)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_push_returns_self
|
36
|
+
pq = FastContainers::PriorityQueue.new(:max)
|
37
|
+
assert_equal pq, pq.push("test",10)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_top_on_a_single_element_queue_returns_that_element
|
41
|
+
pq = FastContainers::PriorityQueue.new(:max);
|
42
|
+
pq.push("test",10)
|
43
|
+
assert_equal "test", pq.top
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_next_on_a_single_element_queue_returns_that_element
|
47
|
+
pq = FastContainers::PriorityQueue.new(:max);
|
48
|
+
pq.push("test",10)
|
49
|
+
assert_equal "test", pq.next
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def test_top_returns_the_maximal_element_in_a_max_queue
|
54
|
+
pq = FastContainers::PriorityQueue.new(:max) # this is a max queue
|
55
|
+
pq.push("10", 10)
|
56
|
+
pq.push("30", 30)
|
57
|
+
pq.push("20", 20)
|
58
|
+
assert_equal "30", pq.top
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_next_returns_the_maximal_element_in_a_max_queue
|
62
|
+
pq = FastContainers::PriorityQueue.new(:max) # this is a max queue
|
63
|
+
pq.push("10", 10)
|
64
|
+
pq.push("30", 30)
|
65
|
+
pq.push("20", 20)
|
66
|
+
assert_equal "30", pq.next
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
def test_top_returns_the_minimal_element_in_a_min_queue
|
71
|
+
pq = FastContainers::PriorityQueue.new(:min) # this is a max queue
|
72
|
+
pq.push("10", 10)
|
73
|
+
pq.push("30", 30)
|
74
|
+
pq.push("20", 20)
|
75
|
+
assert_equal "10", pq.top
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_next_returns_the_minimal_element_in_a_min_queue
|
79
|
+
pq = FastContainers::PriorityQueue.new(:min) # this is a max queue
|
80
|
+
pq.push("10", 10)
|
81
|
+
pq.push("30", 30)
|
82
|
+
pq.push("20", 20)
|
83
|
+
assert_equal "10", pq.next
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_top_key_returns_the_top_priority
|
87
|
+
pq = FastContainers::PriorityQueue.new(:max) # this is a max queue
|
88
|
+
pq.push("10", 10)
|
89
|
+
pq.push("30", 30)
|
90
|
+
pq.push("20", 20)
|
91
|
+
assert_equal 30, pq.top_key
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_next_key_returns_the_top_priority
|
95
|
+
pq = FastContainers::PriorityQueue.new(:max) # this is a max queue
|
96
|
+
pq.push("10", 10)
|
97
|
+
pq.push("30", 30)
|
98
|
+
pq.push("20", 20)
|
99
|
+
assert_equal 30, pq.next_key
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
def test_pop_removes_an_element_from_the_top
|
104
|
+
pq = FastContainers::PriorityQueue.new(:max) # this is a max queue
|
105
|
+
pq.push("10", 10)
|
106
|
+
pq.push("30", 30)
|
107
|
+
pq.push("20", 20)
|
108
|
+
extracted = pq.pop
|
109
|
+
|
110
|
+
assert_equal 20, pq.top_key
|
111
|
+
assert_equal "30", extracted
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_pop_raises_an_exception_if_the_queue_is_empty
|
115
|
+
pq = FastContainers::PriorityQueue.new(:max) # this is a max queue
|
116
|
+
pq.push("10", 10)
|
117
|
+
pq.pop
|
118
|
+
assert_raises(RuntimeError) {
|
119
|
+
pq.pop
|
120
|
+
}
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_empty_returns_false_if_the_queue_is_not_empty
|
124
|
+
pq = FastContainers::PriorityQueue.new(:max) # this is a max queue
|
125
|
+
pq.push("10", 10)
|
126
|
+
assert !pq.empty?
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_empty_returns_true_if_the_queue_is_empty
|
130
|
+
pq = FastContainers::PriorityQueue.new(:max) # this is a max queue
|
131
|
+
assert pq.empty?
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_size_on_empty_queue
|
135
|
+
pq = FastContainers::PriorityQueue.new(:max)
|
136
|
+
assert_equal 0, pq.size
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_size_on_non_empty_queue
|
140
|
+
pq = FastContainers::PriorityQueue.new(:max)
|
141
|
+
pq.push("x",10);
|
142
|
+
pq.push("y",20);
|
143
|
+
pq.push("z",30);
|
144
|
+
assert_equal 3, pq.size
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_enumerable
|
148
|
+
pq = FastContainers::PriorityQueue.new(:max)
|
149
|
+
pq.push(1,10);
|
150
|
+
pq.push(2,20);
|
151
|
+
pq.push(3,30);
|
152
|
+
sum_o = 0
|
153
|
+
sum_p = 0
|
154
|
+
pq.map { |o,p| sum_o+=o; sum_p+=p }
|
155
|
+
assert_equal 6, sum_o
|
156
|
+
assert_equal 60, sum_p
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_top_key_on_empty_queues
|
160
|
+
pq = FastContainers::PriorityQueue.new(:max)
|
161
|
+
assert_nil pq.top_key
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_top_on_empty_queues
|
165
|
+
pq = FastContainers::PriorityQueue.new(:max)
|
166
|
+
assert_nil pq.top
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_second_best_key
|
170
|
+
pq = FastContainers::PriorityQueue.new(:max)
|
171
|
+
pq.push("x", 100);
|
172
|
+
pq.push("y", 80);
|
173
|
+
pq.push("z", 40);
|
174
|
+
pq.push("w", 60);
|
175
|
+
pq.push("i", 90);
|
176
|
+
pq.push("j", 95);
|
177
|
+
|
178
|
+
assert_equal pq.second_best_key, 95
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_second_best_key_on_empty_pq
|
182
|
+
pq = FastContainers::PriorityQueue.new(:max)
|
183
|
+
assert_nil pq.second_best_key
|
184
|
+
end
|
185
|
+
|
186
|
+
def test_second_best_key_on_size_1_pq
|
187
|
+
pq = FastContainers::PriorityQueue.new(:max)
|
188
|
+
pq.push("x", 100)
|
189
|
+
assert_nil pq.second_best_key
|
190
|
+
end
|
191
|
+
|
192
|
+
def test_second_best_key_on_size_2_pq
|
193
|
+
pq = FastContainers::PriorityQueue.new(:max)
|
194
|
+
pq.push("x", 100)
|
195
|
+
pq.push("x", 80)
|
196
|
+
|
197
|
+
assert_equal 80, pq.second_best_key
|
198
|
+
end
|
199
|
+
|
200
|
+
def test_each_will_iterate_over_all_elements
|
201
|
+
pq = FastContainers::PriorityQueue.new(:max);
|
202
|
+
pq.push("x", 100);
|
203
|
+
pq.push("y", 80);
|
204
|
+
pq.push("z", 40);
|
205
|
+
pq.push("w", 60);
|
206
|
+
pq.push("i", 90);
|
207
|
+
pq.push("j", 95);
|
208
|
+
|
209
|
+
objects = Set.new
|
210
|
+
|
211
|
+
result = pq.each do |obj, priority|
|
212
|
+
objects << obj
|
213
|
+
end
|
214
|
+
|
215
|
+
assert_equal objects, Set.new(["x","y","z","w","i","j"])
|
216
|
+
assert_equal pq, result
|
217
|
+
end
|
218
|
+
|
219
|
+
def test_each_will_abort_and_return_nil_if_queue_changes
|
220
|
+
pq = FastContainers::PriorityQueue.new(:max);
|
221
|
+
pq.push("x", 100);
|
222
|
+
pq.push("y", 80);
|
223
|
+
pq.push("z", 40);
|
224
|
+
pq.push("w", 60);
|
225
|
+
pq.push("i", 90);
|
226
|
+
pq.push("j", 95);
|
227
|
+
|
228
|
+
objects = Set.new
|
229
|
+
|
230
|
+
exception = assert_raises RuntimeError do
|
231
|
+
count = 0
|
232
|
+
pq.each do |obj, priority|
|
233
|
+
if count==3
|
234
|
+
pq.push("no way!", 90)
|
235
|
+
end
|
236
|
+
|
237
|
+
count+=1
|
238
|
+
objects << obj
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
assert_match /a change in the priority queue invalidated the current iterator/, exception.message
|
243
|
+
assert_equal 4, objects.size
|
244
|
+
end
|
245
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: priority_queue_cxx
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Roberto Esposito
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake-compiler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: A thin wrapper around C++ priority queues
|
28
|
+
email:
|
29
|
+
- boborbt@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions:
|
32
|
+
- ext/fast_containers/extconf.rb
|
33
|
+
extra_rdoc_files:
|
34
|
+
- README.md
|
35
|
+
files:
|
36
|
+
- README.md
|
37
|
+
- ext/fast_containers/FastContainers.cpp
|
38
|
+
- ext/fast_containers/extconf.rb
|
39
|
+
- ext/fast_containers/fc_pq.cpp
|
40
|
+
- ext/fast_containers/fc_pq.h
|
41
|
+
- lib/fc.rb
|
42
|
+
- test/performance/test_fc_vs_algorithms.rb
|
43
|
+
- test/performance/test_fc_vs_cpriority_queue.rb
|
44
|
+
- test/performance/test_fc_vs_em_priority_queue.rb
|
45
|
+
- test/performance/test_fc_vs_pqueue.rb
|
46
|
+
- test/performance/test_fc_vs_priority_queue.rb
|
47
|
+
- test/test_fast_containers.rb
|
48
|
+
homepage: https://github.com/boborbt/fast_containers
|
49
|
+
licenses:
|
50
|
+
- MIT
|
51
|
+
metadata: {}
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options:
|
54
|
+
- "--main"
|
55
|
+
- README.md
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
requirements: []
|
69
|
+
rubyforge_project:
|
70
|
+
rubygems_version: 2.2.2
|
71
|
+
signing_key:
|
72
|
+
specification_version: 4
|
73
|
+
summary: Fast (c++ wrapper) priority queue implementation for ruby.
|
74
|
+
test_files: []
|
75
|
+
has_rdoc:
|