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 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