min_max 0.1.2 → 0.1.4
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/README.md +18 -3
- data/ext/min_max/src/lib.rs +44 -154
- data/lib/min_max/version.rb +1 -2
- data/lib/min_max.rb +90 -7
- 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: 48b9b64396908ffd54a712e8a8e9b4eb6546e0538a6c168a69d67304dc6fcf1d
|
4
|
+
data.tar.gz: 487b79da6a3a3f99ab408af1feb17ebe33c21c08b7c64b9e20e5b259bcf764bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '086026e3dfe0851390e4090e700aed60a27eaaf70ae53beb9a50164fd78a024797513994b2bd3c67995b29a655c6c8ca755b19ff42797e12190fae9bac10f4c6'
|
7
|
+
data.tar.gz: b7cebaf1da79607d638628c1ef2d54ff11126902e9c1072d4c2bfd1db883db662d323c9e760134c76941747f447494141122e2a4dad6dd0ddc9a65682bfcfd9f
|
data/README.md
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
# MinMax
|
1
|
+
# MinMax Heap
|
2
2
|
|
3
|
-
The MinMax gem provides a high-performance minmax heap implementation for Ruby, written in Rust.
|
4
|
-
|
3
|
+
The MinMax Heap gem provides a high-performance minmax heap implementation for Ruby, written in Rust.
|
4
|
+
The gem wraps the excellent [min-max-heap-rs](https://github.com/tov/min-max-heap-rs) Rust library.
|
5
|
+
It allows for the creation of a min-max-heap and supporting operations like pushing and popping multiple items, iterating over heap items, and converting heaps to arrays.
|
5
6
|
|
6
7
|
## Features
|
7
8
|
|
@@ -23,8 +24,13 @@ Add this line to your application's Gemfile:
|
|
23
24
|
|
24
25
|
```ruby
|
25
26
|
gem 'min_max'
|
27
|
+
|
28
|
+
# or manually specify target . E.g.
|
29
|
+
|
30
|
+
CARGO_BUILD_TARGET=x86_64-apple-darwin gem install min_max
|
26
31
|
```
|
27
32
|
|
33
|
+
|
28
34
|
And then execute:
|
29
35
|
|
30
36
|
```bash
|
@@ -84,4 +90,13 @@ heap.length # Alias for size
|
|
84
90
|
heap.clear
|
85
91
|
```
|
86
92
|
|
93
|
+
## Count number of times an item is in the heap
|
94
|
+
```ruby
|
95
|
+
heap.count(item)
|
96
|
+
```
|
97
|
+
|
98
|
+
## Check if item is contained in the heap
|
99
|
+
```ruby
|
100
|
+
heap.contains?(item)
|
101
|
+
```
|
87
102
|
|
data/ext/min_max/src/lib.rs
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
use magnus::block::Proc;
|
2
1
|
use magnus::scan_args::scan_args;
|
3
2
|
use magnus::value::ReprValue;
|
4
3
|
use magnus::{
|
@@ -7,73 +6,14 @@ use magnus::{
|
|
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
|
-
use std::
|
14
|
-
use std::sync::{Arc, RwLock};
|
12
|
+
use std::rc::Rc;
|
15
13
|
|
16
14
|
#[derive(Debug, Clone)]
|
17
15
|
struct PriorityOrderableValue(i64, i64);
|
18
16
|
|
19
|
-
#[macro_use]
|
20
|
-
extern crate lazy_static;
|
21
|
-
|
22
|
-
struct MEM(
|
23
|
-
RwLock<HashMap<i64, Box<Value>>>,
|
24
|
-
RwLock<HashMap<i64, RefCell<usize>>>,
|
25
|
-
);
|
26
|
-
|
27
|
-
impl MEM {
|
28
|
-
fn new() -> Self {
|
29
|
-
MEM(RwLock::new(HashMap::new()), RwLock::new(HashMap::new()))
|
30
|
-
}
|
31
|
-
}
|
32
|
-
|
33
|
-
unsafe impl Sync for MEM {}
|
34
|
-
|
35
|
-
lazy_static! {
|
36
|
-
static ref MEMORY: MEM = MEM::new();
|
37
|
-
}
|
38
|
-
|
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
17
|
impl PartialOrd for PriorityOrderableValue {
|
78
18
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
79
19
|
Some(self.cmp(other))
|
@@ -82,9 +22,8 @@ impl PartialOrd for PriorityOrderableValue {
|
|
82
22
|
|
83
23
|
impl Ord for PriorityOrderableValue {
|
84
24
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
85
|
-
|
86
|
-
|
87
|
-
}
|
25
|
+
let (PriorityOrderableValue(p1, _), PriorityOrderableValue(p2, _)) = (self, other);
|
26
|
+
p1.cmp(p2)
|
88
27
|
}
|
89
28
|
}
|
90
29
|
|
@@ -92,13 +31,8 @@ impl Eq for PriorityOrderableValue {}
|
|
92
31
|
|
93
32
|
impl PartialEq for PriorityOrderableValue {
|
94
33
|
fn eq(&self, other: &Self) -> bool {
|
95
|
-
|
96
|
-
|
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()
|
100
|
-
}
|
101
|
-
}
|
34
|
+
let (PriorityOrderableValue(p1, v1), PriorityOrderableValue(p2, v2)) = (self, other);
|
35
|
+
p1.eq(p2) && (v1).eq(v2)
|
102
36
|
}
|
103
37
|
}
|
104
38
|
|
@@ -106,50 +40,37 @@ unsafe impl Send for RubyMinMaxHeap {}
|
|
106
40
|
#[derive(DataTypeFunctions, TypedData, Clone)]
|
107
41
|
#[magnus(class = "MinMax", size, free_immediately, mark)]
|
108
42
|
struct RubyMinMaxHeap {
|
109
|
-
heap:
|
110
|
-
priority_proc: Arc<Proc>,
|
43
|
+
heap: Rc<RefCell<MinMaxHeap<PriorityOrderableValue>>>,
|
111
44
|
}
|
112
45
|
|
113
46
|
impl RubyMinMaxHeap {
|
114
|
-
fn new(
|
115
|
-
let args = scan_args::<(), (), (), (), RHash, Option<Proc>>(args)?;
|
116
|
-
let prc: Option<Proc> = args.block;
|
117
|
-
|
47
|
+
fn new() -> Result<Self, Error> {
|
118
48
|
Ok(RubyMinMaxHeap {
|
119
|
-
heap:
|
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(),
|
49
|
+
heap: Rc::new(RefCell::new(MinMaxHeap::new())),
|
128
50
|
})
|
129
51
|
}
|
130
52
|
|
131
|
-
fn push(&self,
|
53
|
+
fn push(&self, values: RArray) -> Result<(), Error> {
|
132
54
|
let mut hp = self.heap.borrow_mut();
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
hp.push(PriorityOrderableValue(priority, push_rb_obj(key, *v)));
|
55
|
+
let values_vec = values.to_vec::<(i64, i64)>().unwrap();
|
56
|
+
values_vec.into_iter().for_each(|(priority, key)| {
|
57
|
+
hp.push(PriorityOrderableValue(priority, key));
|
137
58
|
});
|
138
59
|
Ok(())
|
139
60
|
}
|
140
61
|
|
141
|
-
fn peek_max(&self) -> Result<Option<
|
62
|
+
fn peek_max(&self) -> Result<Option<i64>, Error> {
|
142
63
|
let hp = self.heap.borrow();
|
143
64
|
match hp.peek_max() {
|
144
|
-
Some(PriorityOrderableValue(_, value)) => Ok(
|
65
|
+
Some(PriorityOrderableValue(_, value)) => Ok(Some(*value)),
|
145
66
|
_ => Ok(None),
|
146
67
|
}
|
147
68
|
}
|
148
69
|
|
149
|
-
fn peek_min(&self) -> Result<Option<
|
70
|
+
fn peek_min(&self) -> Result<Option<i64>, Error> {
|
150
71
|
let hp = self.heap.borrow();
|
151
72
|
match hp.peek_min() {
|
152
|
-
Some(PriorityOrderableValue(_, value)) => Ok(
|
73
|
+
Some(PriorityOrderableValue(_, value)) => Ok(Some(*value)),
|
153
74
|
_ => Ok(None),
|
154
75
|
}
|
155
76
|
}
|
@@ -162,20 +83,20 @@ impl RubyMinMaxHeap {
|
|
162
83
|
let mut result = vec![];
|
163
84
|
for _ in 0..c {
|
164
85
|
match { self.heap.borrow_mut() }.pop_max() {
|
165
|
-
Some(PriorityOrderableValue(_, value)) =>
|
166
|
-
result.push(pop_rb_obj(value).unwrap())
|
167
|
-
}
|
86
|
+
Some(PriorityOrderableValue(_, value)) => result.push(Integer::from_i64(value)),
|
168
87
|
_ => break,
|
169
88
|
}
|
170
89
|
}
|
171
90
|
let ary = RArray::new();
|
172
91
|
ary.cat(&result)?;
|
173
|
-
Ok(Some(ary.
|
92
|
+
Ok(Some(ary.as_value()))
|
174
93
|
} else {
|
175
94
|
let mut hp = self.heap.borrow_mut();
|
176
95
|
let val = hp.pop_max();
|
177
96
|
match val {
|
178
|
-
Some(PriorityOrderableValue(_, value)) =>
|
97
|
+
Some(PriorityOrderableValue(_, value)) => {
|
98
|
+
Ok(Some(Integer::from_i64(value).as_value()))
|
99
|
+
}
|
179
100
|
_ => Ok(None),
|
180
101
|
}
|
181
102
|
}
|
@@ -188,19 +109,21 @@ impl RubyMinMaxHeap {
|
|
188
109
|
if let Some(c) = count {
|
189
110
|
let mut result = vec![];
|
190
111
|
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
|
-
}
|
112
|
+
match { self.heap.borrow_mut() }.pop_min() {
|
113
|
+
Some(PriorityOrderableValue(_, value)) => result.push(Integer::from_i64(value)),
|
195
114
|
_ => break,
|
196
115
|
}
|
197
116
|
}
|
198
117
|
let ary = RArray::new();
|
199
118
|
ary.cat(&result)?;
|
200
|
-
Ok(Some(ary.
|
119
|
+
Ok(Some(ary.as_value()))
|
201
120
|
} else {
|
202
|
-
|
203
|
-
|
121
|
+
let mut hp = self.heap.borrow_mut();
|
122
|
+
let val = hp.pop_min();
|
123
|
+
match val {
|
124
|
+
Some(PriorityOrderableValue(_, value)) => {
|
125
|
+
Ok(Some(Integer::from_i64(value).as_value()))
|
126
|
+
}
|
204
127
|
_ => Ok(None),
|
205
128
|
}
|
206
129
|
}
|
@@ -223,45 +146,14 @@ impl RubyMinMaxHeap {
|
|
223
146
|
.into_vec()
|
224
147
|
.into_iter()
|
225
148
|
.map(|orderable_value| match orderable_value {
|
226
|
-
PriorityOrderableValue(_, value) =>
|
149
|
+
PriorityOrderableValue(_, value) => Integer::from_i64(value).as_value(),
|
227
150
|
});
|
228
151
|
Yield::Iter(Box::new(iter))
|
229
152
|
} else {
|
230
|
-
Yield::Enumerator(self.clone().into_value().enumeratorize("
|
153
|
+
Yield::Enumerator(self.clone().into_value().enumeratorize("_each", ()))
|
231
154
|
}
|
232
155
|
}
|
233
156
|
|
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
157
|
fn to_a_asc(&self) -> Result<RArray, Error> {
|
266
158
|
let ary = RArray::new();
|
267
159
|
|
@@ -272,7 +164,7 @@ impl RubyMinMaxHeap {
|
|
272
164
|
.into_vec_asc()
|
273
165
|
.iter()
|
274
166
|
.map(|orderable_value| match orderable_value {
|
275
|
-
PriorityOrderableValue(_, value) =>
|
167
|
+
PriorityOrderableValue(_, value) => Integer::from_i64(*value).as_value(),
|
276
168
|
})
|
277
169
|
.collect();
|
278
170
|
ary.cat(&sorted)?;
|
@@ -289,35 +181,33 @@ impl RubyMinMaxHeap {
|
|
289
181
|
.into_vec_desc()
|
290
182
|
.iter()
|
291
183
|
.map(|orderable_value| match orderable_value {
|
292
|
-
PriorityOrderableValue(_, value) =>
|
184
|
+
PriorityOrderableValue(_, value) => Integer::from_i64(*value).as_value(),
|
293
185
|
})
|
294
186
|
.collect();
|
295
187
|
ary.cat(&sorted)?;
|
296
188
|
Ok(ary)
|
297
189
|
}
|
298
190
|
|
299
|
-
fn clear(&self)
|
300
|
-
|
191
|
+
fn clear(&self) {
|
192
|
+
self.heap.borrow_mut().clear()
|
301
193
|
}
|
302
194
|
}
|
303
195
|
|
304
196
|
#[magnus::init]
|
305
197
|
fn init(ruby: &Ruby) -> Result<(), Error> {
|
306
198
|
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,
|
199
|
+
rb_c_min_max.define_singleton_method("_new", function!(RubyMinMaxHeap::new, 0))?;
|
200
|
+
rb_c_min_max.define_method("_push", method!(RubyMinMaxHeap::push, 1))?;
|
309
201
|
rb_c_min_max.define_method("_pop_max", method!(RubyMinMaxHeap::pop_max, -1))?;
|
310
202
|
rb_c_min_max.define_method("_pop_min", method!(RubyMinMaxHeap::pop_min, -1))?;
|
311
203
|
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))?;
|
204
|
+
rb_c_min_max.define_method("_each", method!(RubyMinMaxHeap::each, 0))?;
|
205
|
+
rb_c_min_max.define_method("_peek_min", method!(RubyMinMaxHeap::peek_min, 0))?;
|
206
|
+
rb_c_min_max.define_method("_peek_max", method!(RubyMinMaxHeap::peek_max, 0))?;
|
207
|
+
rb_c_min_max.define_method("_to_a_asc", method!(RubyMinMaxHeap::to_a_asc, 0))?;
|
208
|
+
rb_c_min_max.define_method("_to_a_desc", method!(RubyMinMaxHeap::to_a_desc, 0))?;
|
318
209
|
rb_c_min_max.define_method("clear", method!(RubyMinMaxHeap::clear, 0))?;
|
319
210
|
rb_c_min_max.define_method("size", method!(RubyMinMaxHeap::size, 0))?;
|
320
211
|
rb_c_min_max.define_method("length", method!(RubyMinMaxHeap::size, 0))?;
|
321
|
-
rb_c_min_max.define_method("inspect", method!(RubyMinMaxHeap::inspect, 0))?;
|
322
212
|
Ok(())
|
323
213
|
}
|
data/lib/min_max/version.rb
CHANGED
data/lib/min_max.rb
CHANGED
@@ -6,28 +6,111 @@ require_relative "min_max/min_max"
|
|
6
6
|
class MinMax
|
7
7
|
class Error < StandardError; end
|
8
8
|
|
9
|
+
attr_reader :priority_blk, :storage, :counts, :mtx
|
10
|
+
|
9
11
|
def self.[](*args, &blk)
|
10
|
-
new(&blk)
|
12
|
+
new(*args, &blk)
|
11
13
|
end
|
12
14
|
|
13
|
-
def
|
14
|
-
|
15
|
+
def self.new(*args, &blk)
|
16
|
+
self._new.tap{|s|
|
17
|
+
s.instance_eval{
|
18
|
+
@priority_blk = (blk || proc{|x| (x.respond_to?(:priority) ? x.priority : x.to_i ) rescue 0})
|
19
|
+
@storage = Hash.new
|
20
|
+
@counts = Hash.new(0)
|
21
|
+
@mtx ||= Mutex.new
|
22
|
+
}
|
23
|
+
s.push(*args)
|
24
|
+
}
|
15
25
|
end
|
16
26
|
|
17
27
|
def push(*args)
|
18
|
-
mtx.synchronize
|
28
|
+
mtx.synchronize do
|
29
|
+
mapped = args.map do |a|
|
30
|
+
self.counts[a.hash] += 1
|
31
|
+
self.storage[a.hash] = a
|
32
|
+
[
|
33
|
+
self.priority_blk.call(a),
|
34
|
+
a.hash
|
35
|
+
]
|
36
|
+
end
|
37
|
+
_push(mapped)
|
38
|
+
end
|
39
|
+
self
|
19
40
|
end
|
20
41
|
|
21
42
|
def add(*args)
|
22
|
-
|
43
|
+
push(*args)
|
23
44
|
end
|
24
45
|
|
25
46
|
def pop_max(*args)
|
26
|
-
mtx.synchronize {
|
47
|
+
mtx.synchronize {
|
48
|
+
popped = _pop_max(*args)
|
49
|
+
popped.kind_of?(Array) ? popped.map{|p| retrieve(p) } : retrieve(popped)
|
50
|
+
}
|
27
51
|
end
|
28
52
|
|
29
53
|
def pop_min(*args)
|
30
|
-
mtx.synchronize {
|
54
|
+
mtx.synchronize {
|
55
|
+
popped = _pop_min(*args)
|
56
|
+
popped.kind_of?(Array) ? popped.map{|p| retrieve(p) } : retrieve(popped)
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
def peek_min(*args)
|
61
|
+
peeked = _peek_min(*args)
|
62
|
+
peeked.kind_of?(Array) ? peeked.map{|p| retrieve(p, false) } : retrieve(popped, false)
|
63
|
+
end
|
64
|
+
|
65
|
+
def peek_max(*args)
|
66
|
+
peeked = _peek_max(*args)
|
67
|
+
peeked.kind_of?(Array) ? peeked.map{|p| retrieve(p, false) } : retrieve(popped, false)
|
68
|
+
end
|
69
|
+
|
70
|
+
def each(*args, &blk)
|
71
|
+
if block_given?
|
72
|
+
mtx.synchronize { _each(*args).map{|p| blk[retrieve(p, false)] } }
|
73
|
+
else
|
74
|
+
to_enum(:each, *args)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def to_a
|
79
|
+
each.to_a
|
80
|
+
end
|
81
|
+
|
82
|
+
def count(val)
|
83
|
+
counts.has_key?(val.hash) ? counts[val.hash] : 0
|
31
84
|
end
|
85
|
+
|
86
|
+
def contains?(val)
|
87
|
+
counts.has_key?(val.hash) && counts[val.hash] > 0
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_a_asc
|
91
|
+
mtx.synchronize { _to_a_asc.map{|p| retrieve(p, false) } }
|
92
|
+
end
|
93
|
+
|
94
|
+
def to_a_desc
|
95
|
+
mtx.synchronize { _to_a_desc.map{|p| retrieve(p, false) } }
|
96
|
+
end
|
97
|
+
|
98
|
+
def inspect
|
99
|
+
"MinMax[#{_each.first(10).map{|v| retrieve(v, false).to_s }.join(", ")}#{size > 10 ? ", ..." : ""}]"
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
def retrieve(hash, remove=true)
|
104
|
+
if remove
|
105
|
+
if (self.counts[hash] -= 1) == 0
|
106
|
+
self.storage.delete(hash)
|
107
|
+
else
|
108
|
+
self.storage[hash]
|
109
|
+
end
|
110
|
+
else
|
111
|
+
self.storage[hash]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
32
115
|
end
|
33
116
|
|
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.4
|
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
|