penguin_queue 0.1.2 → 0.1.3
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/.travis.yml +7 -0
- data/Gemfile.lock +1 -1
- data/README.md +7 -2
- data/ext/penguin_queue/penguin_queue.c +91 -53
- data/lib/penguin_queue/version.rb +1 -1
- data/penguin_queue.gemspec +1 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb2b3114b3a347a0a1f30b0bd72180595e385f4e
|
4
|
+
data.tar.gz: bad8b670607f5eec92c26795de6b0f2217571c5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ae75f4e9505ebe8a27ed745899a493768d46ef51e863f4beb1ce90afb0cbc1145983a05d87c37814cfab2459178fb57c929432d50d438f83afb3fd942ddd1bc
|
7
|
+
data.tar.gz: 8636a9b92b784fae27a3e5870e805ceec105035a533382b0f6c4ad22627b0c621653839f47d90f324dd7a32f0efa120dbab661ae824559b5a846371a3992a6bf
|
data/.travis.yml
ADDED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,9 @@
|
|
1
|
-
#
|
1
|
+
# Penguin Queue
|
2
|
+
|
3
|
+
[](https://travis-ci.org/tompng/penguin_queue)
|
4
|
+
|
5
|
+
Ruby priority-queue library
|
6
|
+
|
2
7
|
```ruby
|
3
8
|
10000.times { array << rand; array.delete(array.min) } #=> slow when array.size is large
|
4
9
|
10000.times { pq << rand; pq.deq } #=> fast even if pq.size is large
|
@@ -38,7 +43,7 @@ pq.size.times.map { pq.deq } #=> [8, 6, 4, 2, 0]
|
|
38
43
|
```ruby
|
39
44
|
# initialize
|
40
45
|
PenguinQueue.new
|
41
|
-
PenguinQueue.new(order) # min(default) or max
|
46
|
+
PenguinQueue.new(order) # :min(default) or :max
|
42
47
|
PenguinQueue.new(&calc_priority_from_element_proc)
|
43
48
|
# enqueue
|
44
49
|
<<(e) enq(e) push(e) unshift(e)
|
@@ -1,12 +1,24 @@
|
|
1
1
|
#include <ruby.h>
|
2
2
|
|
3
|
-
static ID id_priority, id_cmp, id_call,
|
3
|
+
static ID id_priority, id_cmp, id_call, id_max, id_min;
|
4
4
|
#define RB_STR_BUF_CAT(rstr, cstr) rb_str_buf_cat((rstr), (cstr), sizeof(cstr)-1);
|
5
5
|
struct node {
|
6
6
|
long index, id;
|
7
7
|
VALUE queue, priority, value;
|
8
8
|
};
|
9
|
-
|
9
|
+
struct queue_data{
|
10
|
+
long counter;
|
11
|
+
int compare_sgn;
|
12
|
+
VALUE heap, compare_by;
|
13
|
+
};
|
14
|
+
#define NODE_DECLARE_PTR(name) struct node *name;
|
15
|
+
#define NODE_GET_PTR(self, name) Data_Get_Struct(self, struct node, name);
|
16
|
+
#define QUEUE_DECLARE_PTR(name) struct queue_data *name;
|
17
|
+
#define QUEUE_GET_PTR(self, name) Data_Get_Struct(self, struct queue_data, name);
|
18
|
+
#define NODE_PREPARE(self, name) NODE_DECLARE_PTR(name);NODE_GET_PTR(self, name);
|
19
|
+
#define QUEUE_PREPARE(self, name) QUEUE_DECLARE_PTR(name);QUEUE_GET_PTR(self, name);
|
20
|
+
|
21
|
+
VALUE queue_class, node_class;
|
10
22
|
void node_mark(struct node *ptr){
|
11
23
|
rb_gc_mark(ptr->queue);
|
12
24
|
rb_gc_mark(ptr->priority);
|
@@ -21,7 +33,6 @@ VALUE node_alloc_internal(long index, long id, VALUE queue, VALUE priority, VALU
|
|
21
33
|
ptr->value = value;
|
22
34
|
return Data_Wrap_Struct(node_class, node_mark, RUBY_DEFAULT_FREE, ptr);
|
23
35
|
}
|
24
|
-
#define NODE_PREPARE(self, name) struct node *name;Data_Get_Struct(self, struct node, name);
|
25
36
|
VALUE node_pri(VALUE self){
|
26
37
|
NODE_PREPARE(self, ptr);
|
27
38
|
return ptr->priority;
|
@@ -31,8 +42,8 @@ VALUE node_val(VALUE self){
|
|
31
42
|
return ptr->value;
|
32
43
|
}
|
33
44
|
VALUE node_inspect(VALUE self){
|
34
|
-
NODE_PREPARE(self, nptr);
|
35
45
|
VALUE str = rb_str_buf_new(0);
|
46
|
+
NODE_PREPARE(self, nptr);
|
36
47
|
rb_str_buf_append(str, rb_class_name(CLASS_OF(self)));
|
37
48
|
RB_STR_BUF_CAT(str, "{priority: ");
|
38
49
|
rb_str_buf_append(str, rb_inspect(nptr->priority));
|
@@ -42,13 +53,8 @@ VALUE node_inspect(VALUE self){
|
|
42
53
|
return str;
|
43
54
|
}
|
44
55
|
|
45
|
-
struct queue_data{
|
46
|
-
long counter;
|
47
|
-
int compare_sgn;
|
48
|
-
VALUE heap, compare_by;
|
49
|
-
};
|
50
|
-
|
51
56
|
long compare(VALUE a, VALUE b){
|
57
|
+
#ifdef RB_FIXNUM_P
|
52
58
|
if(RB_FIXNUM_P(a)&&RB_FIXNUM_P(b))
|
53
59
|
return (long)a > (long)b ? 1 : (long)a < (long)b ? -1 : 0;
|
54
60
|
if(RB_FLOAT_TYPE_P(a)&&RB_FLOAT_TYPE_P(b)){
|
@@ -57,14 +63,14 @@ long compare(VALUE a, VALUE b){
|
|
57
63
|
}
|
58
64
|
if(RB_TYPE_P(a, T_STRING)&&RB_TYPE_P(b, T_STRING))
|
59
65
|
return rb_str_cmp(a, b);
|
60
|
-
|
61
|
-
|
62
|
-
return
|
66
|
+
return rb_fix2long(rb_funcall(a, id_cmp, 1, b));
|
67
|
+
#else
|
68
|
+
return FIX2LONG(rb_funcall(a, id_cmp, 1, b));
|
69
|
+
#endif
|
63
70
|
}
|
64
71
|
|
65
72
|
long compare_id(long a, long b){return a>b?1:a<b?-1:0;}
|
66
73
|
|
67
|
-
#define QUEUE_PREPARE(self, name) struct queue_data *name;Data_Get_Struct(self, struct queue_data, name);
|
68
74
|
#define OPTHASH_GIVEN_P(opts) (argc > 0 && !NIL_P((opts) = rb_check_hash_type(argv[argc-1])) && (--argc, 1))
|
69
75
|
|
70
76
|
void queue_mark(struct queue_data *self){
|
@@ -87,8 +93,8 @@ VALUE queue_alloc(VALUE klass){
|
|
87
93
|
}
|
88
94
|
|
89
95
|
VALUE queue_initialize(int argc, VALUE *argv, VALUE self){
|
96
|
+
VALUE order;
|
90
97
|
QUEUE_PREPARE(self, ptr);
|
91
|
-
VALUE opts, order;
|
92
98
|
if(argc == 0)return self;
|
93
99
|
rb_scan_args(argc, argv, "1", &order);
|
94
100
|
if(order == ID2SYM(id_max)){
|
@@ -108,16 +114,19 @@ VALUE queue_clear(VALUE self){
|
|
108
114
|
}
|
109
115
|
|
110
116
|
void queue_up(VALUE self, VALUE node){
|
117
|
+
int sgn;
|
111
118
|
QUEUE_PREPARE(self, ptr);
|
112
|
-
|
119
|
+
sgn = ptr->compare_sgn;
|
113
120
|
RARRAY_PTR_USE(ptr->heap, heap, {
|
121
|
+
long index;
|
114
122
|
NODE_PREPARE(node, nptr);
|
115
|
-
|
123
|
+
index = nptr->index;
|
116
124
|
while(index > 1){
|
125
|
+
long cmp;
|
117
126
|
long pindex = index/2;
|
118
127
|
VALUE pnode = heap[pindex];
|
119
128
|
NODE_PREPARE(pnode, pptr);
|
120
|
-
|
129
|
+
cmp = compare(pptr->priority, nptr->priority)*sgn;
|
121
130
|
if(!cmp)cmp=compare_id(pptr->id, nptr->id);
|
122
131
|
if(cmp<0)break;
|
123
132
|
pptr->index = index;
|
@@ -130,20 +139,24 @@ void queue_up(VALUE self, VALUE node){
|
|
130
139
|
}
|
131
140
|
|
132
141
|
void queue_down(VALUE self, VALUE node){
|
142
|
+
int sgn;
|
143
|
+
long length;
|
133
144
|
QUEUE_PREPARE(self, ptr);
|
134
|
-
|
135
|
-
|
145
|
+
sgn = ptr->compare_sgn;
|
146
|
+
length = RARRAY_LEN(ptr->heap);
|
136
147
|
RARRAY_PTR_USE(ptr->heap, heap, {
|
148
|
+
long index;
|
137
149
|
NODE_PREPARE(node, nptr);
|
138
|
-
|
150
|
+
index = nptr->index;
|
139
151
|
while(2*index < length){
|
140
152
|
long lindex = 2*index;
|
141
153
|
VALUE lnode = heap[lindex];
|
142
154
|
NODE_PREPARE(lnode, lptr);
|
143
155
|
if(lindex+1 < length){
|
156
|
+
long cmp;
|
144
157
|
VALUE rnode = heap[lindex+1];
|
145
158
|
NODE_PREPARE(rnode, rptr);
|
146
|
-
|
159
|
+
cmp = compare(lptr->priority, rptr->priority)*sgn;
|
147
160
|
if(!cmp)cmp=compare_id(lptr->id, rptr->id);
|
148
161
|
if(cmp >= 0){
|
149
162
|
lindex += 1;
|
@@ -164,19 +177,24 @@ void queue_down(VALUE self, VALUE node){
|
|
164
177
|
}
|
165
178
|
|
166
179
|
VALUE queue_remove_node(VALUE self, VALUE node){
|
180
|
+
int sgn;
|
181
|
+
long length;
|
182
|
+
QUEUE_DECLARE_PTR(ptr);
|
183
|
+
NODE_DECLARE_PTR(nptr);
|
167
184
|
if(!rb_obj_is_kind_of(node, node_class))return Qnil;
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
185
|
+
QUEUE_GET_PTR(self, ptr);
|
186
|
+
NODE_GET_PTR(node, nptr);
|
187
|
+
sgn = ptr->compare_sgn;
|
188
|
+
length = RARRAY_LEN(ptr->heap);
|
172
189
|
if(nptr->index >= length || RARRAY_AREF(ptr->heap, nptr->index) != node)return Qnil;
|
173
190
|
RARRAY_PTR_USE(ptr->heap, heap, {
|
191
|
+
long cmp;
|
174
192
|
VALUE replace_node = rb_ary_pop(ptr->heap);
|
175
|
-
if(replace_node == node)return Qnil;
|
176
193
|
NODE_PREPARE(replace_node, rptr);
|
194
|
+
if(replace_node == node)return Qnil;
|
177
195
|
heap[nptr->index] = replace_node;
|
178
196
|
rptr->index = nptr->index;
|
179
|
-
|
197
|
+
cmp = compare(rptr->priority, nptr->priority)*sgn;
|
180
198
|
if(!cmp)cmp = compare_id(rptr->id, nptr->id);
|
181
199
|
if(cmp > 0){
|
182
200
|
queue_down(nptr->queue, replace_node);
|
@@ -194,12 +212,17 @@ VALUE node_remove(VALUE self){
|
|
194
212
|
}
|
195
213
|
|
196
214
|
void node_update_priority_internal(VALUE node, VALUE priority){
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
215
|
+
int sgn;
|
216
|
+
long cmp;
|
217
|
+
VALUE priority_was;
|
218
|
+
NODE_DECLARE_PTR(nptr);
|
219
|
+
QUEUE_DECLARE_PTR(ptr);
|
220
|
+
NODE_GET_PTR(node, nptr);
|
221
|
+
QUEUE_GET_PTR(nptr->queue, ptr);
|
222
|
+
sgn = ptr->compare_sgn;
|
223
|
+
priority_was = nptr->priority;
|
201
224
|
nptr->priority = priority;
|
202
|
-
|
225
|
+
cmp = compare(priority, priority_was)*sgn;
|
203
226
|
if(cmp == 0)return;
|
204
227
|
RARRAY_PTR_USE(ptr->heap, heap, {
|
205
228
|
if(heap[nptr->index] != node)return;
|
@@ -212,16 +235,20 @@ void node_update_priority_internal(VALUE node, VALUE priority){
|
|
212
235
|
}
|
213
236
|
|
214
237
|
VALUE node_update_priority(VALUE node, VALUE priority){
|
215
|
-
|
216
|
-
|
238
|
+
NODE_DECLARE_PTR(nptr);
|
239
|
+
QUEUE_DECLARE_PTR(ptr);
|
240
|
+
NODE_GET_PTR(node, nptr);
|
241
|
+
QUEUE_GET_PTR(nptr->queue, ptr);
|
217
242
|
if(ptr->compare_by != Qnil)rb_raise(rb_eRuntimeError, "priority update not supported on queue initialized with block");
|
218
243
|
node_update_priority_internal(node, priority);
|
219
244
|
return priority;
|
220
245
|
}
|
221
246
|
|
222
247
|
VALUE node_update_value(VALUE node, VALUE value){
|
223
|
-
|
224
|
-
|
248
|
+
NODE_DECLARE_PTR(nptr);
|
249
|
+
QUEUE_DECLARE_PTR(ptr);
|
250
|
+
NODE_GET_PTR(node, nptr);
|
251
|
+
QUEUE_GET_PTR(nptr->queue, ptr);
|
225
252
|
nptr->value = value;
|
226
253
|
if(ptr->compare_by != Qnil){
|
227
254
|
VALUE priority = rb_funcall(ptr->compare_by, id_call, 1, value);
|
@@ -231,12 +258,14 @@ VALUE node_update_value(VALUE node, VALUE value){
|
|
231
258
|
}
|
232
259
|
|
233
260
|
VALUE queue_enq_vp(VALUE self, VALUE value, VALUE priority){
|
261
|
+
long length;
|
262
|
+
VALUE node;
|
234
263
|
QUEUE_PREPARE(self, ptr);
|
235
264
|
if(ptr->compare_by != Qnil){
|
236
265
|
priority = rb_funcall(ptr->compare_by, id_call, 1, value);
|
237
266
|
}
|
238
|
-
|
239
|
-
|
267
|
+
length = RARRAY_LEN(ptr->heap);
|
268
|
+
node = node_alloc_internal(length, ptr->counter, self, priority, value);
|
240
269
|
ptr->counter++;
|
241
270
|
rb_ary_push(ptr->heap, node);
|
242
271
|
queue_up(self, node);
|
@@ -258,8 +287,9 @@ VALUE queue_push(VALUE self, VALUE value){
|
|
258
287
|
}
|
259
288
|
|
260
289
|
VALUE queue_first_node(VALUE self){
|
290
|
+
long length;
|
261
291
|
QUEUE_PREPARE(self, ptr);
|
262
|
-
|
292
|
+
length = RARRAY_LEN(ptr->heap);
|
263
293
|
if(length == 1)return Qnil;
|
264
294
|
RARRAY_PTR_USE(ptr->heap, heap, {
|
265
295
|
return heap[1];
|
@@ -267,20 +297,23 @@ VALUE queue_first_node(VALUE self){
|
|
267
297
|
}
|
268
298
|
VALUE queue_first(VALUE self){
|
269
299
|
VALUE node = queue_first_node(self);
|
300
|
+
NODE_DECLARE_PTR(nptr);
|
270
301
|
if(node == Qnil)return Qnil;
|
271
|
-
|
302
|
+
NODE_GET_PTR(node, nptr);
|
272
303
|
return nptr->value;
|
273
304
|
}
|
274
305
|
VALUE queue_first_with_priority(VALUE self){
|
275
306
|
VALUE node = queue_first_node(self);
|
307
|
+
NODE_DECLARE_PTR(nptr);
|
276
308
|
if(node == Qnil)return Qnil;
|
277
|
-
|
309
|
+
NODE_GET_PTR(node, nptr);
|
278
310
|
return rb_ary_new_from_args(2, nptr->value, nptr->priority);
|
279
311
|
}
|
280
312
|
|
281
313
|
VALUE queue_deq_node(VALUE self){
|
314
|
+
long length;
|
282
315
|
QUEUE_PREPARE(self, ptr);
|
283
|
-
|
316
|
+
length = RARRAY_LEN(ptr->heap);
|
284
317
|
if(length == 1)return Qnil;
|
285
318
|
RARRAY_PTR_USE(ptr->heap, heap, {
|
286
319
|
VALUE first = heap[1];
|
@@ -296,19 +329,23 @@ VALUE queue_deq_node(VALUE self){
|
|
296
329
|
VALUE queue_deq(int argc, VALUE *argv, VALUE self){
|
297
330
|
if(argc == 0){
|
298
331
|
VALUE node = queue_deq_node(self);
|
332
|
+
NODE_DECLARE_PTR(nptr);
|
299
333
|
if(node == Qnil)return Qnil;
|
300
|
-
|
334
|
+
NODE_GET_PTR(node, nptr);
|
301
335
|
return nptr->value;
|
302
336
|
}else{
|
303
|
-
VALUE nv;
|
337
|
+
VALUE nv, result;
|
338
|
+
int i;
|
339
|
+
long n, length;
|
340
|
+
QUEUE_DECLARE_PTR(ptr);
|
304
341
|
rb_scan_args(argc, argv, "1", &nv);
|
305
|
-
|
342
|
+
n = NUM2LONG(nv);
|
306
343
|
if(n<0)rb_raise(rb_eArgError, "negative array size");
|
307
|
-
|
308
|
-
|
344
|
+
QUEUE_GET_PTR(self, ptr);
|
345
|
+
length = RARRAY_LEN(ptr->heap)-1;
|
309
346
|
if(n>length)n=length;
|
310
|
-
|
311
|
-
for(
|
347
|
+
result = rb_ary_new_capa(n);
|
348
|
+
for(i=0;i<n;i++){
|
312
349
|
VALUE node = queue_deq_node(self);
|
313
350
|
NODE_PREPARE(node, nptr);
|
314
351
|
rb_ary_push(result, nptr->value);
|
@@ -318,8 +355,9 @@ VALUE queue_deq(int argc, VALUE *argv, VALUE self){
|
|
318
355
|
}
|
319
356
|
VALUE queue_deq_with_priority(VALUE self){
|
320
357
|
VALUE node = queue_deq_node(self);
|
358
|
+
NODE_DECLARE_PTR(nptr);
|
321
359
|
if(node == Qnil)return Qnil;
|
322
|
-
|
360
|
+
NODE_GET_PTR(node, nptr);
|
323
361
|
return rb_ary_new_from_args(2, nptr->value, nptr->priority);
|
324
362
|
}
|
325
363
|
|
@@ -341,8 +379,8 @@ VALUE queue_is_max(VALUE self){
|
|
341
379
|
return QUEUE_PTR_IS_MIN(ptr) ? Qfalse : Qtrue;
|
342
380
|
}
|
343
381
|
VALUE queue_inspect(VALUE self){
|
344
|
-
QUEUE_PREPARE(self, ptr);
|
345
382
|
VALUE str = rb_str_buf_new(0);
|
383
|
+
QUEUE_PREPARE(self, ptr);
|
346
384
|
rb_str_buf_append(str, rb_class_name(CLASS_OF(self)));
|
347
385
|
RB_STR_BUF_CAT(str, "{order: ");
|
348
386
|
if(QUEUE_PTR_IS_MIN(ptr)){
|
@@ -363,7 +401,7 @@ void Init_penguin_queue(void){
|
|
363
401
|
id_max = rb_intern("max");
|
364
402
|
id_min = rb_intern("min");
|
365
403
|
|
366
|
-
|
404
|
+
queue_class = rb_define_class("PenguinQueue", rb_cObject);
|
367
405
|
rb_define_alloc_func(queue_class, queue_alloc);
|
368
406
|
rb_define_method(queue_class, "initialize", queue_initialize, -1);
|
369
407
|
rb_define_method(queue_class, "size", queue_size, 0);
|
data/penguin_queue.gemspec
CHANGED
@@ -13,6 +13,7 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.description = %q{C Ext Priority Queue (binary heap)}
|
14
14
|
spec.homepage = "https://github.com/tompng/penguin_queue"
|
15
15
|
spec.license = "MIT"
|
16
|
+
spec.required_ruby_version = '>= 2.2.0'
|
16
17
|
spec.extensions = %w[ext/penguin_queue/extconf.rb]
|
17
18
|
|
18
19
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: penguin_queue
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- tompng
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-02-
|
11
|
+
date: 2017-02-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -75,6 +75,7 @@ extensions:
|
|
75
75
|
extra_rdoc_files: []
|
76
76
|
files:
|
77
77
|
- ".gitignore"
|
78
|
+
- ".travis.yml"
|
78
79
|
- Gemfile
|
79
80
|
- Gemfile.lock
|
80
81
|
- LICENSE.txt
|
@@ -99,7 +100,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
99
100
|
requirements:
|
100
101
|
- - ">="
|
101
102
|
- !ruby/object:Gem::Version
|
102
|
-
version:
|
103
|
+
version: 2.2.0
|
103
104
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
105
|
requirements:
|
105
106
|
- - ">="
|