min_max 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/ext/min_max/src/lib.rs +38 -123
- data/lib/min_max/version.rb +1 -2
- data/lib/min_max.rb +87 -5
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5b1020f3ac8e632e3b2b4d99318a78edf48a06d3099e5812637d8dfd5fdf1623
|
4
|
+
data.tar.gz: b774055ca657edf4a01712a71020cbb55df034e38f3db676b0c85484ae1f155e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c7a1e0c3893382526f5c94c488618a3d01b7e19aa3a6d1b3cfc0aa012ede494bfb033c1b9544224bcfa3f9147d3d96779d11c83f2723a384c36109c5f837dba
|
7
|
+
data.tar.gz: 4c60344475780f72a7369cac4fc0a22e156750fee690b326a2cbc9b6d1c492446f05dbdda5e39910e9f9549b848730ade850fda8e282d418ba1fa0e8e8c19793
|
data/ext/min_max/src/lib.rs
CHANGED
@@ -1,13 +1,12 @@
|
|
1
|
-
use magnus::block::Proc;
|
2
1
|
use magnus::scan_args::scan_args;
|
3
|
-
use magnus::value::ReprValue;
|
2
|
+
use magnus::value::{BoxValue, ReprValue};
|
4
3
|
use magnus::{
|
5
4
|
block::{block_given, Yield},
|
6
5
|
define_class, function, method,
|
7
6
|
prelude::*,
|
8
7
|
Error, IntoValue, RArray, Ruby, Value,
|
9
8
|
};
|
10
|
-
use magnus::{
|
9
|
+
use magnus::{DataTypeFunctions, Integer, TypedData};
|
11
10
|
use min_max_heap::MinMaxHeap;
|
12
11
|
use std::cell::RefCell;
|
13
12
|
use std::collections::HashMap;
|
@@ -20,7 +19,7 @@ struct PriorityOrderableValue(i64, i64);
|
|
20
19
|
extern crate lazy_static;
|
21
20
|
|
22
21
|
struct MEM(
|
23
|
-
RwLock<HashMap<i64,
|
22
|
+
RwLock<HashMap<i64, BoxValue<Value>>>,
|
24
23
|
RwLock<HashMap<i64, RefCell<usize>>>,
|
25
24
|
);
|
26
25
|
|
@@ -36,44 +35,6 @@ lazy_static! {
|
|
36
35
|
static ref MEMORY: MEM = MEM::new();
|
37
36
|
}
|
38
37
|
|
39
|
-
fn get_rb_obj(key: i64) -> Option<Value> {
|
40
|
-
let binding = (*MEMORY).0.read().unwrap();
|
41
|
-
let v = binding.get(&key).unwrap();
|
42
|
-
Some(**v)
|
43
|
-
}
|
44
|
-
|
45
|
-
fn pop_rb_obj(key: i64) -> Option<Value> {
|
46
|
-
let binding = (*MEMORY).1.read().unwrap();
|
47
|
-
let mut count = binding.get(&key).unwrap().borrow_mut();
|
48
|
-
if *count == 0 {
|
49
|
-
return None;
|
50
|
-
}
|
51
|
-
*count -= 1;
|
52
|
-
let res = if *count == 0 {
|
53
|
-
let val = (*MEMORY).0.write().unwrap().remove(&key).unwrap();
|
54
|
-
gc::unregister_address(&*val);
|
55
|
-
Some(*val)
|
56
|
-
} else {
|
57
|
-
let binding = (*MEMORY).0.read().unwrap();
|
58
|
-
let v = binding.get(&key).unwrap();
|
59
|
-
Some(**v)
|
60
|
-
};
|
61
|
-
res
|
62
|
-
}
|
63
|
-
|
64
|
-
fn push_rb_obj(key: i64, value: Value) -> i64 {
|
65
|
-
let mut binding = (*MEMORY).1.write().unwrap();
|
66
|
-
let mut count = binding.entry(key).or_insert(RefCell::new(0)).borrow_mut();
|
67
|
-
|
68
|
-
*count += 1;
|
69
|
-
if *count == 1 {
|
70
|
-
let boxed = Box::new(value);
|
71
|
-
gc::register_address(&*boxed);
|
72
|
-
(*MEMORY).0.write().unwrap().insert(key, boxed);
|
73
|
-
};
|
74
|
-
return key;
|
75
|
-
}
|
76
|
-
|
77
38
|
impl PartialOrd for PriorityOrderableValue {
|
78
39
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
79
40
|
Some(self.cmp(other))
|
@@ -94,9 +55,7 @@ impl PartialEq for PriorityOrderableValue {
|
|
94
55
|
fn eq(&self, other: &Self) -> bool {
|
95
56
|
match (self, other) {
|
96
57
|
(PriorityOrderableValue(p1, v1), PriorityOrderableValue(p2, v2)) => {
|
97
|
-
|
98
|
-
let v2_obj = get_rb_obj(*v2).unwrap();
|
99
|
-
p1.eq(p2) && (v1_obj).eql(v2_obj).unwrap_or_default()
|
58
|
+
p1.eq(p2) && (v1).eq(v2)
|
100
59
|
}
|
101
60
|
}
|
102
61
|
}
|
@@ -107,49 +66,36 @@ unsafe impl Send for RubyMinMaxHeap {}
|
|
107
66
|
#[magnus(class = "MinMax", size, free_immediately, mark)]
|
108
67
|
struct RubyMinMaxHeap {
|
109
68
|
heap: Arc<RefCell<MinMaxHeap<PriorityOrderableValue>>>,
|
110
|
-
priority_proc: Arc<Proc>,
|
111
69
|
}
|
112
70
|
|
113
71
|
impl RubyMinMaxHeap {
|
114
|
-
fn new(
|
115
|
-
let args = scan_args::<(), (), (), (), RHash, Option<Proc>>(args)?;
|
116
|
-
let prc: Option<Proc> = args.block;
|
117
|
-
|
72
|
+
fn new() -> Result<Self, Error> {
|
118
73
|
Ok(RubyMinMaxHeap {
|
119
74
|
heap: Arc::new(RefCell::new(MinMaxHeap::new())),
|
120
|
-
priority_proc: prc
|
121
|
-
.unwrap_or_else(|| {
|
122
|
-
let value: Value =
|
123
|
-
eval("Proc.new {|x| x.respond_to?(:priority) ? x.priority : x.to_i }")
|
124
|
-
.unwrap();
|
125
|
-
Proc::from_value(value).unwrap()
|
126
|
-
})
|
127
|
-
.into(),
|
128
75
|
})
|
129
76
|
}
|
130
77
|
|
131
|
-
fn push(&self,
|
78
|
+
fn push(&self, values: RArray) -> Result<(), Error> {
|
132
79
|
let mut hp = self.heap.borrow_mut();
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
hp.push(PriorityOrderableValue(priority, push_rb_obj(key, *v)));
|
80
|
+
let values_vec = values.to_vec::<(i64, i64)>().unwrap();
|
81
|
+
values_vec.into_iter().for_each(|(priority, key)| {
|
82
|
+
hp.push(PriorityOrderableValue(priority, key));
|
137
83
|
});
|
138
84
|
Ok(())
|
139
85
|
}
|
140
86
|
|
141
|
-
fn peek_max(&self) -> Result<Option<
|
87
|
+
fn peek_max(&self) -> Result<Option<i64>, Error> {
|
142
88
|
let hp = self.heap.borrow();
|
143
89
|
match hp.peek_max() {
|
144
|
-
Some(PriorityOrderableValue(_, value)) => Ok(
|
90
|
+
Some(PriorityOrderableValue(_, value)) => Ok(Some(*value)),
|
145
91
|
_ => Ok(None),
|
146
92
|
}
|
147
93
|
}
|
148
94
|
|
149
|
-
fn peek_min(&self) -> Result<Option<
|
95
|
+
fn peek_min(&self) -> Result<Option<i64>, Error> {
|
150
96
|
let hp = self.heap.borrow();
|
151
97
|
match hp.peek_min() {
|
152
|
-
Some(PriorityOrderableValue(_, value)) => Ok(
|
98
|
+
Some(PriorityOrderableValue(_, value)) => Ok(Some(*value)),
|
153
99
|
_ => Ok(None),
|
154
100
|
}
|
155
101
|
}
|
@@ -162,20 +108,20 @@ impl RubyMinMaxHeap {
|
|
162
108
|
let mut result = vec![];
|
163
109
|
for _ in 0..c {
|
164
110
|
match { self.heap.borrow_mut() }.pop_max() {
|
165
|
-
Some(PriorityOrderableValue(_, value)) =>
|
166
|
-
result.push(pop_rb_obj(value).unwrap())
|
167
|
-
}
|
111
|
+
Some(PriorityOrderableValue(_, value)) => result.push(Integer::from_i64(value)),
|
168
112
|
_ => break,
|
169
113
|
}
|
170
114
|
}
|
171
115
|
let ary = RArray::new();
|
172
116
|
ary.cat(&result)?;
|
173
|
-
Ok(Some(ary.
|
117
|
+
Ok(Some(ary.as_value()))
|
174
118
|
} else {
|
175
119
|
let mut hp = self.heap.borrow_mut();
|
176
120
|
let val = hp.pop_max();
|
177
121
|
match val {
|
178
|
-
Some(PriorityOrderableValue(_, value)) =>
|
122
|
+
Some(PriorityOrderableValue(_, value)) => {
|
123
|
+
Ok(Some(Integer::from_i64(value).as_value()))
|
124
|
+
}
|
179
125
|
_ => Ok(None),
|
180
126
|
}
|
181
127
|
}
|
@@ -188,19 +134,21 @@ impl RubyMinMaxHeap {
|
|
188
134
|
if let Some(c) = count {
|
189
135
|
let mut result = vec![];
|
190
136
|
for _ in 0..c {
|
191
|
-
match { self.heap.borrow_mut().pop_min()
|
192
|
-
Some(PriorityOrderableValue(_, value)) =>
|
193
|
-
result.push(pop_rb_obj(value).unwrap())
|
194
|
-
}
|
137
|
+
match { self.heap.borrow_mut() }.pop_min() {
|
138
|
+
Some(PriorityOrderableValue(_, value)) => result.push(Integer::from_i64(value)),
|
195
139
|
_ => break,
|
196
140
|
}
|
197
141
|
}
|
198
142
|
let ary = RArray::new();
|
199
143
|
ary.cat(&result)?;
|
200
|
-
Ok(Some(ary.
|
144
|
+
Ok(Some(ary.as_value()))
|
201
145
|
} else {
|
202
|
-
|
203
|
-
|
146
|
+
let mut hp = self.heap.borrow_mut();
|
147
|
+
let val = hp.pop_min();
|
148
|
+
match val {
|
149
|
+
Some(PriorityOrderableValue(_, value)) => {
|
150
|
+
Ok(Some(Integer::from_i64(value).as_value()))
|
151
|
+
}
|
204
152
|
_ => Ok(None),
|
205
153
|
}
|
206
154
|
}
|
@@ -223,45 +171,14 @@ impl RubyMinMaxHeap {
|
|
223
171
|
.into_vec()
|
224
172
|
.into_iter()
|
225
173
|
.map(|orderable_value| match orderable_value {
|
226
|
-
PriorityOrderableValue(_, value) =>
|
174
|
+
PriorityOrderableValue(_, value) => Integer::from_i64(value).as_value(),
|
227
175
|
});
|
228
176
|
Yield::Iter(Box::new(iter))
|
229
177
|
} else {
|
230
|
-
Yield::Enumerator(self.clone().into_value().enumeratorize("
|
178
|
+
Yield::Enumerator(self.clone().into_value().enumeratorize("_each", ()))
|
231
179
|
}
|
232
180
|
}
|
233
181
|
|
234
|
-
fn to_a(&self) -> Result<RArray, Error> {
|
235
|
-
let each: Value = self.clone().into_value().funcall("each", ())?;
|
236
|
-
Ok(each.funcall("to_a", ())?)
|
237
|
-
}
|
238
|
-
|
239
|
-
fn inspect(&self) -> Result<RString, Error> {
|
240
|
-
let mut visited = std::collections::HashSet::new();
|
241
|
-
Ok(self.build_inspect(&mut visited)?)
|
242
|
-
}
|
243
|
-
|
244
|
-
fn build_inspect(
|
245
|
-
&self,
|
246
|
-
visited: &mut std::collections::HashSet<*const Self>,
|
247
|
-
) -> Result<RString, Error> {
|
248
|
-
// Check for circular reference
|
249
|
-
if !visited.insert(self as *const Self) {
|
250
|
-
return Ok(RString::new("[Circular Reference Detected]"));
|
251
|
-
}
|
252
|
-
|
253
|
-
let to_a: Value = self.to_a()?.into_value();
|
254
|
-
let r: String = match to_a.funcall("inspect", ()) {
|
255
|
-
Ok(inspect_value) => inspect_value,
|
256
|
-
Err(_) => return Ok(RString::new("[Error inspecting array]")),
|
257
|
-
};
|
258
|
-
|
259
|
-
// Ensure the current object is removed from the visited set to allow re-visiting in future calls
|
260
|
-
visited.remove(&(self as *const Self));
|
261
|
-
|
262
|
-
Ok(RString::new(&format!("MinMax{}", r)))
|
263
|
-
}
|
264
|
-
|
265
182
|
fn to_a_asc(&self) -> Result<RArray, Error> {
|
266
183
|
let ary = RArray::new();
|
267
184
|
|
@@ -272,7 +189,7 @@ impl RubyMinMaxHeap {
|
|
272
189
|
.into_vec_asc()
|
273
190
|
.iter()
|
274
191
|
.map(|orderable_value| match orderable_value {
|
275
|
-
PriorityOrderableValue(_, value) =>
|
192
|
+
PriorityOrderableValue(_, value) => Integer::from_i64(*value).as_value(),
|
276
193
|
})
|
277
194
|
.collect();
|
278
195
|
ary.cat(&sorted)?;
|
@@ -289,7 +206,7 @@ impl RubyMinMaxHeap {
|
|
289
206
|
.into_vec_desc()
|
290
207
|
.iter()
|
291
208
|
.map(|orderable_value| match orderable_value {
|
292
|
-
PriorityOrderableValue(_, value) =>
|
209
|
+
PriorityOrderableValue(_, value) => Integer::from_i64(*value).as_value(),
|
293
210
|
})
|
294
211
|
.collect();
|
295
212
|
ary.cat(&sorted)?;
|
@@ -304,20 +221,18 @@ impl RubyMinMaxHeap {
|
|
304
221
|
#[magnus::init]
|
305
222
|
fn init(ruby: &Ruby) -> Result<(), Error> {
|
306
223
|
let rb_c_min_max = define_class("MinMax", ruby.class_object())?;
|
307
|
-
rb_c_min_max.define_singleton_method("
|
308
|
-
rb_c_min_max.define_method("_push", method!(RubyMinMaxHeap::push,
|
224
|
+
rb_c_min_max.define_singleton_method("_new", function!(RubyMinMaxHeap::new, 0))?;
|
225
|
+
rb_c_min_max.define_method("_push", method!(RubyMinMaxHeap::push, 1))?;
|
309
226
|
rb_c_min_max.define_method("_pop_max", method!(RubyMinMaxHeap::pop_max, -1))?;
|
310
227
|
rb_c_min_max.define_method("_pop_min", method!(RubyMinMaxHeap::pop_min, -1))?;
|
311
228
|
rb_c_min_max.define_method("empty?", method!(RubyMinMaxHeap::is_empty, 0))?;
|
312
|
-
rb_c_min_max.define_method("
|
313
|
-
rb_c_min_max.define_method("
|
314
|
-
rb_c_min_max.define_method("
|
315
|
-
rb_c_min_max.define_method("
|
316
|
-
rb_c_min_max.define_method("
|
317
|
-
rb_c_min_max.define_method("to_a_desc", method!(RubyMinMaxHeap::to_a_desc, 0))?;
|
229
|
+
rb_c_min_max.define_method("_each", method!(RubyMinMaxHeap::each, 0))?;
|
230
|
+
rb_c_min_max.define_method("_peek_min", method!(RubyMinMaxHeap::peek_min, 0))?;
|
231
|
+
rb_c_min_max.define_method("_peek_max", method!(RubyMinMaxHeap::peek_max, 0))?;
|
232
|
+
rb_c_min_max.define_method("_to_a_asc", method!(RubyMinMaxHeap::to_a_asc, 0))?;
|
233
|
+
rb_c_min_max.define_method("_to_a_desc", method!(RubyMinMaxHeap::to_a_desc, 0))?;
|
318
234
|
rb_c_min_max.define_method("clear", method!(RubyMinMaxHeap::clear, 0))?;
|
319
235
|
rb_c_min_max.define_method("size", method!(RubyMinMaxHeap::size, 0))?;
|
320
236
|
rb_c_min_max.define_method("length", method!(RubyMinMaxHeap::size, 0))?;
|
321
|
-
rb_c_min_max.define_method("inspect", method!(RubyMinMaxHeap::inspect, 0))?;
|
322
237
|
Ok(())
|
323
238
|
}
|
data/lib/min_max/version.rb
CHANGED
data/lib/min_max.rb
CHANGED
@@ -7,7 +7,26 @@ class MinMax
|
|
7
7
|
class Error < StandardError; end
|
8
8
|
|
9
9
|
def self.[](*args, &blk)
|
10
|
-
new(&blk)
|
10
|
+
new(*args, &blk)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.new(*args, &blk)
|
14
|
+
self._new.tap{|s|
|
15
|
+
s.priority_blk =(blk || proc{|x| (x.respond_to?(:priority) ? x.priority : x.to_i ) rescue 0})
|
16
|
+
s.push(*args)
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def priority_blk=(bll)
|
21
|
+
@priority_blk = bll
|
22
|
+
end
|
23
|
+
|
24
|
+
def storage
|
25
|
+
@storage ||= Hash.new
|
26
|
+
end
|
27
|
+
|
28
|
+
def counts
|
29
|
+
@counts ||= Hash.new(0)
|
11
30
|
end
|
12
31
|
|
13
32
|
def mtx
|
@@ -15,19 +34,82 @@ class MinMax
|
|
15
34
|
end
|
16
35
|
|
17
36
|
def push(*args)
|
18
|
-
mtx.synchronize
|
37
|
+
mtx.synchronize do
|
38
|
+
mapped = args.map do |a|
|
39
|
+
counts[a.hash] += 1
|
40
|
+
storage[a.hash] = a
|
41
|
+
[
|
42
|
+
@priority_blk.call(a),
|
43
|
+
a.hash
|
44
|
+
]
|
45
|
+
end
|
46
|
+
_push(mapped)
|
47
|
+
end
|
48
|
+
self
|
19
49
|
end
|
20
50
|
|
21
51
|
def add(*args)
|
22
|
-
|
52
|
+
push(*args)
|
23
53
|
end
|
24
54
|
|
25
55
|
def pop_max(*args)
|
26
|
-
mtx.synchronize {
|
56
|
+
mtx.synchronize {
|
57
|
+
popped = _pop_max(*args)
|
58
|
+
popped.kind_of?(Array) ? popped.map{|p| retrieve(p) } : retrieve(popped)
|
59
|
+
}
|
27
60
|
end
|
28
61
|
|
29
62
|
def pop_min(*args)
|
30
|
-
mtx.synchronize {
|
63
|
+
mtx.synchronize {
|
64
|
+
popped = _pop_min(*args)
|
65
|
+
popped.kind_of?(Array) ? popped.map{|p| retrieve(p) } : retrieve(popped)
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
def retrieve(hash, remove=true)
|
70
|
+
if remove
|
71
|
+
if (counts[hash] -= 1) == 0
|
72
|
+
storage.delete(hash)
|
73
|
+
else
|
74
|
+
storage[hash]
|
75
|
+
end
|
76
|
+
else
|
77
|
+
storage[hash]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def peek_min(*args)
|
82
|
+
peeked = _peek_min(*args)
|
83
|
+
peeked.kind_of?(Array) ? peeked.map{|p| retrieve(p, false) } : retrieve(popped, false)
|
84
|
+
end
|
85
|
+
|
86
|
+
def peek_max(*args)
|
87
|
+
peeked = _peek_max(*args)
|
88
|
+
peeked.kind_of?(Array) ? peeked.map{|p| retrieve(p, false) } : retrieve(popped, false)
|
89
|
+
end
|
90
|
+
|
91
|
+
def each(*args, &blk)
|
92
|
+
if block_given?
|
93
|
+
mtx.synchronize { _each(*args).map{|p| blk[retrieve(p, false)] } }
|
94
|
+
else
|
95
|
+
to_enum(:each, *args)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def to_a
|
100
|
+
each.to_a
|
101
|
+
end
|
102
|
+
|
103
|
+
def to_a_asc
|
104
|
+
mtx.synchronize { _to_a_asc.map{|p| retrieve(p, false) } }
|
105
|
+
end
|
106
|
+
|
107
|
+
def to_a_desc
|
108
|
+
mtx.synchronize { _to_a_desc.map{|p| retrieve(p, false) } }
|
109
|
+
end
|
110
|
+
|
111
|
+
def inspect
|
112
|
+
"MinMax[#{to_a_asc.first(10).map{|v| v.to_s}.join(", ")}#{size > 10 ? ", ..." : ""}]"
|
31
113
|
end
|
32
114
|
end
|
33
115
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: min_max
|
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
|
- Wouter Coppieters
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-02-
|
11
|
+
date: 2024-02-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rb_sys
|