Skip to content

Commit 3f5e461

Browse files
committed
0.0.2: add element insert/remove, shrink_to_fit
1 parent 5c70a66 commit 3f5e461

File tree

5 files changed

+162
-30
lines changed

5 files changed

+162
-30
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "range-set"
3-
version = "0.0.1"
3+
version = "0.0.2"
44
authors = ["Shane Pearman <[email protected]>"]
55
license = "Apache-2.0"
66

README.md

+49-11
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
# `range-set`
22

3-
> Store a collection of contiguous `PrimInt` values as inclusive ranges using
4-
> generic `SmallVec` storage
3+
> Store collections of `PrimInt` values as inclusive ranges using generic
4+
> `SmallVec`-backed storage.
55
6-
This is useful when you want to process elements in order when they are not
7-
quite perfectly contiguous. Having a generic `smallvec::Array` parameter allows
6+
[Documentation](https://spearman.github.io/range-set/range_set/index.html)
7+
8+
This is useful when you want to process elements in order but they are not
9+
perfectly contiguous. Having a generic `smallvec::Array` parameter allows
810
choosing how many ranges will fit on the stack before spilling over onto the
911
heap:
1012

@@ -26,14 +28,44 @@ let v : Vec <u8> = s.iter().collect();
2628
assert_eq!(v, vec![0,1,2,3,4,5,6,7,8,9,10,11,12]);
2729
```
2830

31+
2932
## Usage
3033

31-
TODO
34+
Inclusive ranges are an unstable Rust feature (as of `rustc` 1.24) so they must
35+
be enabled in the crate root:
36+
37+
```rust
38+
#![feature(inclusive_range)]
39+
#![feature(inclusive_range_syntax)]
40+
41+
extern crate range_set;
42+
```
3243

33-
## Memory usage characteristics
44+
```rust
45+
use range_set::RangeSet;
46+
use std::ops::RangeInclusive;
47+
let mut s = RangeSet::<[RangeInclusive <u32>; 2]>::from_ranges (vec![
48+
1..=100,
49+
500..=1000
50+
].into()).unwrap();
51+
s.insert (200);
52+
s.insert (400..=499);
53+
assert_eq!(s, RangeSet::from_ranges (vec![
54+
1..=100,
55+
200..=200,
56+
400..=1000
57+
].into()).unwrap());
58+
```
3459

35-
The top-level `report` function will report byte sizes for various sizes of
36-
integers and array sizes. An program calling this function can be found in
60+
See `./examples/example.rs` and documentation for more examples.
61+
62+
63+
## Performance characteristics
64+
65+
**Memory**
66+
67+
The top-level `report` function will report byte sizes for various integers and
68+
array sizes. A program calling this function can be found in
3769
`./examples/example.rs`. Example output:
3870

3971
```
@@ -66,6 +98,12 @@ RangeSet report...
6698
...RangeSet report
6799
```
68100

69-
As can be seen, using this for byte ranges is not a good idea since the minimum
70-
usage is 32 bytes which is enough to store the full range of 256 values as
71-
individual bits (32 * 8 = 256).
101+
As can be seen, using this type for `u8` (byte) ranges is not a good idea since
102+
the minimum usage is 32 bytes which is enough to store the full range of 256
103+
values as individual bits (32 * 8 = 256).
104+
105+
106+
**Time complexity**
107+
108+
Since the ranges are stored in sorted order, binary search is used when
109+
inserting and removing values.

TODO

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
- remove
2-
- merge
3-
- more set operations
1+
- set operations
2+
- union
3+
- intersection
4+
- difference

examples/example.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ fn main() {
2020

2121
assert_eq!(s.insert_range (3..=12), Some (RangeSet::from (8..=10)));
2222
println!("s: {:?}", s);
23-
assert!(!s.spilled());
23+
assert!(s.spilled());
2424
let v : Vec <u8> = s.iter().collect();
2525
assert_eq!(v, vec![0,1,2,3,4,5,6,7,8,9,10,11,12]);
2626

2727
assert_eq!(s.remove_range (0..=2), Some (RangeSet::from (0..=2)));
2828
println!("s: {:?}", s);
29-
assert!(!s.spilled());
29+
assert!(s.spilled());
3030
let v : Vec <u8> = s.iter().collect();
3131
assert_eq!(v, vec![3,4,5,6,7,8,9,10,11,12]);
3232

@@ -51,15 +51,15 @@ fn main() {
5151

5252
assert_eq!(s.remove_range (5..=20), Some (RangeSet::from (11..=12)));
5353
println!("s: {:?}", s);
54-
// /!\ spilled status does not get reset here
55-
//assert!(!s.spilled());
54+
assert!(s.spilled()); // stays spilled
55+
s.shrink_to_fit(); // manually un-spill
56+
assert!(!s.spilled()); // no longer spilled
5657
let v : Vec <u8> = s.iter().collect();
5758
assert_eq!(v, vec![3,4]);
5859

5960
assert_eq!(s.remove_range (0..=10), Some (RangeSet::from (3..=4)));
6061
println!("s: {:?}", s);
61-
// /!\ spilled status does not get reset here
62-
//assert!(!s.spilled());
62+
assert!(!s.spilled());
6363
let v : Vec <u8> = s.iter().collect();
6464
assert_eq!(v, vec![]);
6565
}

src/lib.rs

+102-9
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ pub use range_compare::{
1616
// structs //
1717
///////////////////////////////////////////////////////////////////////////////
1818

19-
/// A set of elements represented as a sorted list of inclusive ranges.
19+
/// A set of primitive integers represented as a sorted list of inclusive
20+
/// ranges.
2021
///
2122
/// ```
2223
/// # #![feature(inclusive_range)]
@@ -39,9 +40,11 @@ pub use range_compare::{
3940
///
4041
/// assert_eq!(s.insert_range (3..=12), Some (RangeSet::from (8..=10)));
4142
/// println!("s: {:?}", s);
42-
/// assert!(!s.spilled());
43+
/// assert!(s.spilled()); // once spilled, stays spilled
4344
/// let v : Vec <u32> = s.iter().collect();
4445
/// assert_eq!(v, vec![0,1,2,3,4,5,6,7,8,9,10,11,12]);
46+
/// s.shrink_to_fit(); // manually un-spill
47+
/// assert!(!s.spilled());
4548
/// # }
4649
/// ```
4750
#[derive(Clone,Debug,Eq,PartialEq)]
@@ -134,6 +137,11 @@ pub fn report() {
134137
// impls //
135138
///////////////////////////////////////////////////////////////////////////////
136139

140+
// the majority of the logic for modifying range sets are the insert_range and
141+
// remove_range methods
142+
//
143+
// there are some helper functions with additional logic such as the
144+
// binary_search functions
137145
impl <A, T> RangeSet <A> where
138146
A : smallvec::Array <Item=std::ops::RangeInclusive <T>>
139147
+ Eq + std::fmt::Debug,
@@ -147,6 +155,15 @@ impl <A, T> RangeSet <A> where
147155
}
148156
}
149157

158+
/// New empty range set with the internal smallvec initialized with the given
159+
/// initial capacity
160+
#[inline]
161+
pub fn with_capacity (capacity : usize) -> Self {
162+
RangeSet {
163+
ranges: smallvec::SmallVec::with_capacity (capacity)
164+
}
165+
}
166+
150167
/// Returns a new range set if the given vector of ranges is valid
151168
/// (`valid_range_vec`)
152169
#[inline]
@@ -164,6 +181,78 @@ impl <A, T> RangeSet <A> where
164181
self.ranges.is_empty()
165182
}
166183

184+
/// Clears the range set
185+
#[inline]
186+
pub fn clear (&mut self) {
187+
self.ranges.clear()
188+
}
189+
190+
/// Converts into the internal smallvec
191+
#[inline]
192+
pub fn into_smallvec (self) -> smallvec::SmallVec <A> {
193+
self.ranges
194+
}
195+
196+
/// Insert a single element, returning true if it was successfully inserted
197+
/// or else false if it was already present
198+
///
199+
/// ```
200+
/// # #![feature(inclusive_range)]
201+
/// # #![feature(inclusive_range_syntax)]
202+
/// # use range_set::RangeSet;
203+
/// # use std::ops::RangeInclusive;
204+
/// let mut s = RangeSet::<[RangeInclusive <u32>; 2]>::new();
205+
/// assert!(s.insert (4));
206+
/// assert_eq!(s, RangeSet::from (4..=4));
207+
/// assert!(!s.insert (4));
208+
/// assert_eq!(s, RangeSet::from (4..=4));
209+
/// assert!(s.insert (5));
210+
/// assert_eq!(s, RangeSet::from (4..=5));
211+
/// assert!(s.insert (3));
212+
/// assert_eq!(s, RangeSet::from (3..=5));
213+
/// assert!(s.insert (10));
214+
/// assert_eq!(s, RangeSet::from_ranges (vec![3..=5, 10..=10].into()).unwrap());
215+
/// ```
216+
pub fn insert (&mut self, element : T) -> bool {
217+
if let Some (_) = self.insert_range (element..=element) {
218+
false
219+
} else {
220+
true
221+
}
222+
}
223+
224+
/// Remove a single element, returning true if it was successfully removed
225+
/// or else false if it was not present
226+
///
227+
/// ```
228+
/// # #![feature(inclusive_range)]
229+
/// # #![feature(inclusive_range_syntax)]
230+
/// # use range_set::RangeSet;
231+
/// # use std::ops::RangeInclusive;
232+
/// let mut s = RangeSet::<[RangeInclusive <u32>; 2]>::from (0..=5);
233+
/// assert!(s.remove (1));
234+
/// assert_eq!(s, RangeSet::from_ranges (vec![0..=0, 2..=5].into()).unwrap());
235+
/// assert!(!s.remove (1));
236+
/// assert_eq!(s, RangeSet::from_ranges (vec![0..=0, 2..=5].into()).unwrap());
237+
/// assert!(s.remove (4));
238+
/// assert_eq!(s, RangeSet::from_ranges (vec![0..=0, 2..=3, 5..=5].into()).unwrap());
239+
/// assert!(s.remove (3));
240+
/// assert_eq!(s, RangeSet::from_ranges (vec![0..=0, 2..=2, 5..=5].into()).unwrap());
241+
/// assert!(s.remove (2));
242+
/// assert_eq!(s, RangeSet::from_ranges (vec![0..=0, 5..=5].into()).unwrap());
243+
/// assert!(s.remove (0));
244+
/// assert_eq!(s, RangeSet::from (5..=5));
245+
/// assert!(s.remove (5));
246+
/// assert!(s.is_empty());
247+
/// ```
248+
pub fn remove (&mut self, element : T) -> bool {
249+
if let Some (_) = self.remove_range (element..=element) {
250+
true
251+
} else {
252+
false
253+
}
254+
}
255+
167256
/// Returns the intersected values if the range is not disjoint
168257
/// with the curret range set.
169258
///
@@ -194,13 +283,11 @@ impl <A, T> RangeSet <A> where
194283
// of the intersection of the given range and the existing range set
195284
(None, None) => {
196285
let isect = self.range_intersection (&range, 0..self.ranges.len());
197-
self.ranges = {
198-
let mut v = smallvec::SmallVec::new();
199-
v.push (
200-
std::cmp::min (range.start, self.ranges[0].start)..=
201-
std::cmp::max (range.end, self.ranges[self.ranges.len()-1].end));
202-
v
203-
};
286+
let new_range =
287+
std::cmp::min (range.start, self.ranges[0].start)..=
288+
std::cmp::max (range.end, self.ranges[self.ranges.len()-1].end);
289+
self.ranges.clear();
290+
self.ranges.push (new_range);
204291
if !isect.is_empty() {
205292
Some (isect)
206293
} else {
@@ -411,6 +498,12 @@ impl <A, T> RangeSet <A> where
411498
self.ranges.spilled()
412499
}
413500

501+
/// Calls `shrink_to_fit` on the underlying smallvec
502+
#[inline]
503+
pub fn shrink_to_fit (&mut self) {
504+
self.ranges.shrink_to_fit()
505+
}
506+
414507
/// Insert helper function: search for the last range in self that is
415508
/// `LessThanAdjacent` or `LessThanProper` when compared with the given range
416509
fn binary_search_before (&self, range : &A::Item) -> Option <usize> {

0 commit comments

Comments
 (0)