min_max 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aef5e878c1412daa7a16bf7aad72afff1bdcc4cfa37709e6a88601d6ef2f1a93
4
- data.tar.gz: 74f22abb3ad7a47e654cf6033d0512e00344a373e21aa18e46f86a9d38e6dc17
3
+ metadata.gz: 5b1020f3ac8e632e3b2b4d99318a78edf48a06d3099e5812637d8dfd5fdf1623
4
+ data.tar.gz: b774055ca657edf4a01712a71020cbb55df034e38f3db676b0c85484ae1f155e
5
5
  SHA512:
6
- metadata.gz: 0b992bc50cd6e4920503b8a9257916dc3cb83326126c9e56c38fb693bbf513335573f8c7730386109044de48f58dd6e8a9c1da7f4a6e91e9f28e2aeb981cd23c
7
- data.tar.gz: e5f84db084190697f2d8ab7738b70fc82ae2b4a23466936d47e74aef27e46dd39f1f2e5885b1a7d3f876f28aadc0dfc747dabffe36c05eaa3f4661f7424091bf
6
+ metadata.gz: 2c7a1e0c3893382526f5c94c488618a3d01b7e19aa3a6d1b3cfc0aa012ede494bfb033c1b9544224bcfa3f9147d3d96779d11c83f2723a384c36109c5f837dba
7
+ data.tar.gz: 4c60344475780f72a7369cac4fc0a22e156750fee690b326a2cbc9b6d1c492446f05dbdda5e39910e9f9549b848730ade850fda8e282d418ba1fa0e8e8c19793
@@ -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::{eval, gc, DataTypeFunctions, RHash, RString, TypedData};
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, Box<Value>>>,
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
- let v1_obj = get_rb_obj(*v1).unwrap();
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(args: &[Value]) -> Result<Self, Error> {
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, value: &[Value]) -> Result<(), Error> {
78
+ fn push(&self, values: RArray) -> Result<(), Error> {
132
79
  let mut hp = self.heap.borrow_mut();
133
- value.iter().for_each(|v| {
134
- let priority: i64 = (*self.priority_proc).call([*v]).unwrap_or_default();
135
- let key = v.hash().unwrap().to_i64().unwrap();
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<Value>, Error> {
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(get_rb_obj(*value)),
90
+ Some(PriorityOrderableValue(_, value)) => Ok(Some(*value)),
145
91
  _ => Ok(None),
146
92
  }
147
93
  }
148
94
 
149
- fn peek_min(&self) -> Result<Option<Value>, Error> {
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(get_rb_obj(*value)),
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.into_value()))
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)) => Ok(pop_rb_obj(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.into_value()))
144
+ Ok(Some(ary.as_value()))
201
145
  } else {
202
- match { self.heap.borrow_mut().pop_min() } {
203
- Some(PriorityOrderableValue(_, value)) => Ok(pop_rb_obj(value)),
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) => get_rb_obj(value).unwrap(),
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("each", ()))
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) => get_rb_obj(*value).unwrap(),
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) => get_rb_obj(*value).unwrap(),
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("new", function!(RubyMinMaxHeap::new, -1))?;
308
- rb_c_min_max.define_method("_push", method!(RubyMinMaxHeap::push, -1))?;
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("each", method!(RubyMinMaxHeap::each, 0))?;
313
- rb_c_min_max.define_method("peek_min", method!(RubyMinMaxHeap::peek_min, 0))?;
314
- rb_c_min_max.define_method("peek_max", method!(RubyMinMaxHeap::peek_max, 0))?;
315
- rb_c_min_max.define_method("to_a", method!(RubyMinMaxHeap::to_a, 0))?;
316
- rb_c_min_max.define_method("to_a_asc", method!(RubyMinMaxHeap::to_a_asc, 0))?;
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
  }
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class MinMax
4
- VERSION = "0.1.2"
5
-
4
+ VERSION = "0.1.3"
6
5
  end
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).tap{|s| s.push(*args) }
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 { _push(*args) }
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
- mtx.synchronize { _push(*args) }
52
+ push(*args)
23
53
  end
24
54
 
25
55
  def pop_max(*args)
26
- mtx.synchronize { _pop_max(*args) }
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 { _pop_min(*args) }
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.2
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-24 00:00:00.000000000 Z
11
+ date: 2024-02-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rb_sys