use std::collections::BTreeSet;
use std::fmt;
use thiserror::Error;
pub const AUTOSTEP_DISABLED: f64 = 1e100;
#[derive(Debug, Error)]
pub enum RangeSetError {
#[error("parse error: {msg} (in \"{part}\")")]
ParseError { part: String, msg: String },
#[error("padding mismatch: {msg} (in \"{part}\")")]
PaddingError { part: String, msg: String },
}
pub type Result<T> = std::result::Result<T, RangeSetError>;
fn sort_key(s: &str) -> (i64, i64, String) {
if s.starts_with('-') {
let ival: i64 = s.parse().unwrap_or(0);
(-(s.len() as i64), ival, String::new())
} else {
(s.len() as i64, 0, s.to_string())
}
}
fn sorted_elements(elements: &BTreeSet<String>) -> Vec<String> {
let mut v: Vec<String> = elements.iter().cloned().collect();
v.sort_by(|a, b| sort_key(a).cmp(&sort_key(b)));
v
}
#[derive(Debug, Clone)]
struct RangeSlice {
start: i64,
stop: i64, step: i64,
pad: usize,
}
#[derive(Debug, Clone)]
pub struct RangeSet {
elements: BTreeSet<String>,
_autostep: f64,
}
impl RangeSet {
pub fn new() -> Self {
Self {
elements: BTreeSet::new(),
_autostep: AUTOSTEP_DISABLED,
}
}
pub fn parse(pattern: &str, autostep: Option<u32>) -> Result<Self> {
let mut rs = Self::new();
rs.set_autostep(autostep);
rs._parse(pattern)?;
Ok(rs)
}
fn _parse(&mut self, pattern: &str) -> Result<()> {
for subrange in pattern.split(',') {
let subrange = subrange.trim();
let (baserange, step) = if subrange.contains('/') {
let parts: Vec<&str> = subrange.splitn(2, '/').collect();
let step_str = parts[1];
let step: i64 = step_str.parse().map_err(|_| RangeSetError::ParseError {
part: subrange.to_string(),
msg: "cannot convert string to integer".to_string(),
})?;
(parts[0], step)
} else {
(subrange, 1i64)
};
let (begin_str, end_str, _begin_sign, _end_sign) =
self.parse_range_part(baserange, subrange, step)?;
let (start, stop, pad) = self.compute_padding(&begin_str, &end_str, subrange)?;
if stop > 1e100 as i64 || start > stop || step < 1 {
return Err(RangeSetError::ParseError {
part: subrange.to_string(),
msg: "invalid values in range".to_string(),
});
}
self.add_range(start, stop + 1, step, pad as u32);
}
Ok(())
}
fn parse_range_part<'a>(
&self,
baserange: &'a str,
subrange: &str,
step: i64,
) -> Result<(String, String, i64, i64)> {
if !baserange.contains('-') {
if step != 1 {
return Err(RangeSetError::ParseError {
part: subrange.to_string(),
msg: "invalid step usage".to_string(),
});
}
return Ok((baserange.to_string(), baserange.to_string(), 1, 1));
}
let parts: Vec<&str> = baserange.split('-').collect();
match parts.len() {
2 => {
let begin = parts[0].trim().to_string();
let end = parts[1].trim().to_string();
if begin.is_empty() {
if end.is_empty() {
return Err(RangeSetError::ParseError {
part: subrange.to_string(),
msg: "cannot convert string to integer".to_string(),
});
}
return Ok((end.clone(), end, -1, -1));
}
Ok((begin, end, 1, 1))
}
3 => {
let begin = parts[1].trim().to_string();
let end = parts[2].trim().to_string();
Ok((begin, end, -1, 1))
}
4 => {
let begin = parts[1].trim().to_string();
let end = parts[3].trim().to_string();
Ok((begin, end, -1, -1))
}
_ => Err(RangeSetError::ParseError {
part: subrange.to_string(),
msg: "cannot convert string to integer".to_string(),
}),
}
}
fn compute_padding(&self, begin: &str, end: &str, subrange: &str) -> Result<(i64, i64, usize)> {
let mut pad: usize = 0;
let begin_int: i64 = begin.parse().map_err(|_| {
if subrange.is_empty() {
RangeSetError::ParseError {
part: subrange.to_string(),
msg: "empty range".to_string(),
}
} else {
RangeSetError::ParseError {
part: subrange.to_string(),
msg: "cannot convert string to integer".to_string(),
}
}
})?;
if begin_int != 0 {
let begins = begin.trim_start_matches('0');
if begin.len() - begins.len() > 0 {
pad = begin.len();
}
} else if begin.len() > 1 {
pad = begin.len();
}
let end_trimmed = if end.parse::<i64>().unwrap_or(1) != 0 {
end.trim_start_matches('0')
} else {
end
};
let mut endpad: usize = 0;
if end.len() - end_trimmed.len() > 0 {
endpad = end.len();
}
if (pad > 0 || endpad > 0) && begin.len() != end.len() {
return Err(RangeSetError::ParseError {
part: subrange.to_string(),
msg: "padding length mismatch".to_string(),
});
}
let end_int: i64 = end_trimmed.parse().map_err(|_| RangeSetError::ParseError {
part: subrange.to_string(),
msg: "cannot convert string to integer".to_string(),
})?;
Ok((begin_int, end_int, pad))
}
pub fn add_range(&mut self, start: i64, stop: i64, step: i64, pad: u32) {
assert!(start < stop, "please provide ordered node index ranges");
assert!(step > 0);
assert!(stop - start < 1_000_000_000, "range too large");
let mut i = start;
while i < stop {
if pad == 0 {
self.elements.insert(format!("{}", i));
} else {
self.elements
.insert(format!("{:0>width$}", i, width = pad as usize));
}
i += step;
}
}
pub fn len(&self) -> usize {
self.elements.len()
}
pub fn is_empty(&self) -> bool {
self.elements.is_empty()
}
pub fn add_str(&mut self, s: &str) {
self.elements.insert(s.to_string());
}
pub fn add_int(&mut self, value: i64, pad: u32) {
if pad == 0 {
self.elements.insert(format!("{}", value));
} else {
self.elements
.insert(format!("{:0>width$}", value, width = pad as usize));
}
}
pub fn remove_str(&mut self, s: &str) {
if !self.elements.remove(s) {
panic!("element '{}' not found in RangeSet", s);
}
}
pub fn discard_str(&mut self, s: &str) {
self.elements.remove(s);
}
pub fn contains_str(&self, s: &str) -> bool {
self.elements.contains(s)
}
pub fn contains_int(&self, value: i64) -> bool {
self.elements.contains(&format!("{}", value))
}
pub fn sorted(&self) -> Vec<String> {
sorted_elements(&self.elements)
}
pub fn striter(&self) -> impl Iterator<Item = String> {
sorted_elements(&self.elements).into_iter()
}
pub fn intiter(&self) -> impl Iterator<Item = i64> {
sorted_elements(&self.elements)
.into_iter()
.map(|s| s.parse::<i64>().unwrap_or(0))
}
pub fn union(&self, other: &RangeSet) -> RangeSet {
let mut result = self.clone();
result.update(other);
result
}
pub fn intersection(&self, other: &RangeSet) -> RangeSet {
let mut result = self.clone();
result.intersection_update(other);
result
}
pub fn difference(&self, other: &RangeSet) -> RangeSet {
let mut result = self.clone();
result.difference_update(other);
result
}
pub fn symmetric_difference(&self, other: &RangeSet) -> RangeSet {
let mut result = self.clone();
result.symmetric_difference_update(other);
result
}
pub fn update(&mut self, other: &RangeSet) {
for elem in &other.elements {
self.elements.insert(elem.clone());
}
}
pub fn intersection_update(&mut self, other: &RangeSet) {
self.elements = self
.elements
.intersection(&other.elements)
.cloned()
.collect();
}
pub fn difference_update(&mut self, other: &RangeSet) {
self.elements = self.elements.difference(&other.elements).cloned().collect();
}
pub fn symmetric_difference_update(&mut self, other: &RangeSet) {
self.elements = self
.elements
.symmetric_difference(&other.elements)
.cloned()
.collect();
}
pub fn autostep(&self) -> Option<u32> {
if self._autostep >= AUTOSTEP_DISABLED {
None
} else {
Some((self._autostep as u32) + 1)
}
}
pub fn set_autostep(&mut self, val: Option<u32>) {
match val {
None => self._autostep = AUTOSTEP_DISABLED,
Some(v) => self._autostep = (v as f64) - 1.0,
}
}
fn slices_padding(&self, autostep: f64) -> Vec<RangeSlice> {
let sorted = sorted_elements(&self.elements);
if sorted.is_empty() {
return Vec::new();
}
let mut result: Vec<RangeSlice> = Vec::new();
let mut cur_pad: usize = 0;
let mut cur_padded: bool = false;
let mut cur_start: Option<i64> = None;
let mut cur_step: Option<i64> = None;
let mut last_idx: i64 = 0;
for si in &sorted {
let idx: i64 = si.parse().unwrap_or(0);
let digitlen = si.len();
let padded = digitlen > 1 && si.starts_with('0');
if let Some(cs) = cur_start {
let padding_mismatch = if cur_padded {
digitlen != cur_pad
} else {
padded
};
let step_mismatch = if let Some(cstep) = cur_step {
cstep != idx - last_idx
} else {
false
};
if padding_mismatch || step_mismatch {
let (stepped, step) = if let Some(cstep) = cur_step {
let stepped =
(cstep == 1) || ((last_idx - cs) as f64 >= autostep * cstep as f64);
(stepped, cstep)
} else {
(true, 1i64)
};
if stepped {
result.push(RangeSlice {
start: cs,
stop: last_idx + 1,
step,
pad: if cur_padded { cur_pad } else { 0 },
});
cur_start = Some(idx);
cur_padded = padded;
cur_pad = digitlen;
} else {
if padding_mismatch {
let stop = last_idx + 1;
let mut j = cs;
while j < stop {
result.push(RangeSlice {
start: j,
stop: j + 1,
step: 1,
pad: if cur_padded { cur_pad } else { 0 },
});
j += step;
}
cur_start = Some(idx);
cur_padded = padded;
cur_pad = digitlen;
} else {
let stop = last_idx - step + 1;
let mut j = cs;
while j < stop {
result.push(RangeSlice {
start: j,
stop: j + 1,
step: 1,
pad: if cur_padded { cur_pad } else { 0 },
});
j += step;
}
cur_start = Some(last_idx);
}
}
cur_step = if step_mismatch {
Some(idx - last_idx)
} else {
None
};
last_idx = idx;
continue;
}
} else {
cur_padded = padded;
cur_pad = digitlen;
cur_start = Some(idx);
cur_step = None;
last_idx = idx;
continue;
}
cur_step = Some(idx - last_idx);
last_idx = idx;
}
if let Some(cs) = cur_start {
if let Some(cstep) = cur_step {
let stepped = (last_idx - cs) as f64 >= self._autostep * cstep as f64;
if stepped || cstep == 1 {
result.push(RangeSlice {
start: cs,
stop: last_idx + 1,
step: cstep,
pad: if cur_padded { cur_pad } else { 0 },
});
} else {
let mut j = cs;
while j <= last_idx {
result.push(RangeSlice {
start: j,
stop: j + 1,
step: 1,
pad: if cur_padded { cur_pad } else { 0 },
});
j += cstep;
}
}
} else {
result.push(RangeSlice {
start: cs,
stop: last_idx + 1,
step: 1,
pad: if cur_padded { cur_pad } else { 0 },
});
}
}
result
}
fn folded_slices(&self) -> Vec<RangeSlice> {
self.slices_padding(self._autostep)
}
fn strslices(&self) -> Vec<String> {
self.folded_slices()
.iter()
.map(|sli| {
if sli.start + 1 == sli.stop {
if sli.pad > 0 {
format!("{:0>width$}", sli.start, width = sli.pad)
} else {
format!("{}", sli.start)
}
} else if sli.step == 1 {
if sli.pad > 0 {
format!(
"{:0>width$}-{:0>width$}",
sli.start,
sli.stop - 1,
width = sli.pad
)
} else {
format!("{}-{}", sli.start, sli.stop - 1)
}
} else {
if sli.pad > 0 {
format!(
"{:0>width$}-{:0>width$}/{}",
sli.start,
sli.stop - 1,
sli.step,
width = sli.pad
)
} else {
format!("{}-{}/{}", sli.start, sli.stop - 1, sli.step)
}
}
})
.collect()
}
pub fn padding(&self) -> Option<usize> {
let mut result = None;
for si in sorted_elements(&self.elements) {
let digitlen = si.len();
if digitlen > 1 && si.starts_with('0') {
result = Some(digitlen);
}
}
result
}
}
impl Default for RangeSet {
fn default() -> Self {
Self::new()
}
}
impl fmt::Display for RangeSet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.strslices().join(","))
}
}
#[derive(Debug, Clone)]
pub struct RangeSetND {
pub vecrangesets: Vec<Vec<RangeSet>>,
_autostep: f64,
}
impl RangeSetND {
pub fn new(autostep: Option<u32>) -> Self {
Self {
vecrangesets: Vec::new(),
_autostep: autostep.map(|v| v as f64).unwrap_or(AUTOSTEP_DISABLED),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn test_rs(input: &str, expected: &str, expected_len: usize) {
let rs = RangeSet::parse(input, Some(3)).unwrap();
assert_eq!(
rs.to_string(),
expected,
"parse '{}' display mismatch",
input
);
assert_eq!(rs.len(), expected_len, "parse '{}' len mismatch", input);
}
#[test]
fn test_simple() {
test_rs("0", "0", 1);
test_rs("1", "1", 1);
test_rs("0-2", "0-2", 3);
test_rs("1-3", "1-3", 3);
test_rs("1-3,4-6", "1-6", 6);
test_rs("1-3,4-6,7-10", "1-10", 10);
}
#[test]
fn test_step_simple() {
test_rs("0-4/2", "0-4/2", 3);
test_rs("1-4/2", "1,3", 2);
test_rs("1-4/3", "1,4", 2);
test_rs("1-4/4", "1", 1);
}
#[test]
fn test_step_advanced() {
test_rs("1-4/4,2-6/2", "1-2,4,6", 4);
test_rs("6-24/6,9-21/6", "6-24/3", 7);
test_rs("0-24/2,9-21/2", "0-8/2,9-22,24", 20);
test_rs("0-24/2,9-21/2,100", "0-8/2,9-22,24,100", 21);
test_rs("3-21/9,6-24/9,9-27/9", "3-27/3", 9);
test_rs("1-17/2,2-18/2", "1-18", 18);
test_rs("1-17/01", "1-17", 17);
test_rs("1-17/02", "1-17/2", 9);
test_rs("1-17/03", "1-16/3", 6);
}
#[test]
fn test_step_advanced_more() {
test_rs("0-24/2,9-21/2,100-101", "0-8/2,9-22,24,100-101", 22);
test_rs("101-121/4,1-225/112", "1,101-121/4,225", 8);
test_rs("1-32/3,13-28/9", "1-31/3", 11);
test_rs("1-32/3,13-22/9", "1-31/3", 11);
test_rs("1-32/3,13-31/9", "1-31/3", 11);
test_rs("1-32/3,13-40/9", "1-31/3,40", 12);
}
#[test]
fn test_step_more_complex() {
test_rs("1-16/3,13-28/6", "1-19/3,25", 8);
test_rs("1-16/3,1-16/6", "1-16/3", 6);
test_rs("1-16/6,1-16/3", "1-16/3", 6);
test_rs("1-17/2,33-41/2,2-18/2", "1-18,33-41/2", 23);
test_rs("1-17/2,33-41/2,2-20/2", "1-18,20,33-41/2", 24);
test_rs("1-17/2,33-41/2,2-19/2", "1-18,33-41/2", 23);
}
#[test]
fn test_bad_syntax() {
assert!(RangeSet::parse("", None).is_err());
assert!(RangeSet::parse("-", None).is_err());
assert!(RangeSet::parse("A", None).is_err());
assert!(RangeSet::parse("2-5/a", None).is_err());
assert!(RangeSet::parse("3/2", None).is_err());
assert!(RangeSet::parse("3-/2", None).is_err());
assert!(RangeSet::parse("-/2", None).is_err());
assert!(RangeSet::parse("4-a/2", None).is_err());
assert!(RangeSet::parse("4-3/2", None).is_err());
assert!(RangeSet::parse("4-5/-2", None).is_err());
assert!(RangeSet::parse("004-002", None).is_err());
}
#[test]
fn test_intersection() {
let mut r1 = RangeSet::parse("4-34", None).unwrap();
let r2 = RangeSet::parse("27-42", None).unwrap();
r1.intersection_update(&r2);
assert_eq!(r1.to_string(), "27-34");
assert_eq!(r1.len(), 8);
}
#[test]
fn test_intersection_complex() {
let mut r1 = RangeSet::parse("2-450,654-700,800", None).unwrap();
let r2 = RangeSet::parse("500-502,690-820,830-840,900", None).unwrap();
r1.intersection_update(&r2);
assert_eq!(r1.to_string(), "690-700,800");
assert_eq!(r1.len(), 12);
}
#[test]
fn test_intersection_step() {
let mut r1 = RangeSet::parse("4-34/2", None).unwrap();
let r2 = RangeSet::parse("28-42/2", None).unwrap();
r1.intersection_update(&r2);
assert_eq!(r1.to_string(), "28,30,32,34");
assert_eq!(r1.len(), 4);
let mut r1 = RangeSet::parse("4-34/2", None).unwrap();
let r2 = RangeSet::parse("27-42/2", None).unwrap();
r1.intersection_update(&r2);
assert_eq!(r1.to_string(), "");
assert_eq!(r1.len(), 0);
let mut r1 = RangeSet::parse("2-60/3", Some(3)).unwrap();
let r2 = RangeSet::parse("3-50/2", Some(3)).unwrap();
r1.intersection_update(&r2);
assert_eq!(r1.to_string(), "5-47/6");
assert_eq!(r1.len(), 8);
}
#[test]
fn test_difference() {
let mut r1 = RangeSet::parse("4,7-33", None).unwrap();
let r2 = RangeSet::parse("8-33", None).unwrap();
r1.difference_update(&r2);
assert_eq!(r1.to_string(), "4,7");
assert_eq!(r1.len(), 2);
}
#[test]
fn test_difference_bounds() {
let mut r1 = RangeSet::parse("1-10,39-41,50-60", None).unwrap();
let r2 = RangeSet::parse("1-10,38-39,50-60", None).unwrap();
r1.difference_update(&r2);
assert_eq!(r1.len(), 2);
assert_eq!(r1.to_string(), "40-41");
}
#[test]
fn test_symmetric_difference() {
let mut r1 = RangeSet::parse("4,7-33", None).unwrap();
let r2 = RangeSet::parse("8-34", None).unwrap();
r1.symmetric_difference_update(&r2);
assert_eq!(r1.to_string(), "4,7,34");
assert_eq!(r1.len(), 3);
}
#[test]
fn test_symmetric_difference_complex() {
let mut r1 = RangeSet::parse("5,7,10-12,33-50", None).unwrap();
let r2 = RangeSet::parse("8-34", None).unwrap();
r1.symmetric_difference_update(&r2);
assert_eq!(r1.to_string(), "5,7-9,13-32,35-50");
assert_eq!(r1.len(), 40);
let mut r1 = RangeSet::parse("8-30", None).unwrap();
let r2 = RangeSet::parse("31-40", None).unwrap();
r1.symmetric_difference_update(&r2);
assert_eq!(r1.to_string(), "8-40");
assert_eq!(r1.len(), 33);
let mut r1 = RangeSet::parse("8-30", None).unwrap();
let r2 = RangeSet::parse("8-30", None).unwrap();
r1.symmetric_difference_update(&r2);
assert_eq!(r1.to_string(), "");
assert_eq!(r1.len(), 0);
}
#[test]
fn test_union() {
let r1 = RangeSet::parse("1-10", None).unwrap();
let r2 = RangeSet::parse("8-20", None).unwrap();
let r3 = r1.union(&r2);
assert_eq!(r3.to_string(), "1-20");
assert_eq!(r3.len(), 20);
}
#[test]
fn test_contains() {
let r1 = RangeSet::parse("1-100,102,105-242,800", None).unwrap();
assert_eq!(r1.len(), 240);
assert!(r1.contains_str("99"));
assert!(!r1.contains_str("099"));
assert!(!r1.contains_str("101"));
}
#[test]
fn test_padding() {
let r1 = RangeSet::parse("001-010", None).unwrap();
assert_eq!(r1.len(), 10);
assert!(r1.contains_str("001"));
assert!(r1.contains_str("010"));
assert!(!r1.contains_str("1"));
assert!(!r1.contains_str("10"));
let r2 = RangeSet::parse("00-02", None).unwrap();
assert!(r2.contains_str("00"));
assert!(!r2.contains_str("0"));
assert!(r2.contains_str("01"));
assert!(!r2.contains_str("1"));
let r3 = RangeSet::parse("0003-0143,0360-1000", None).unwrap();
assert!(!r3.contains_str("360"));
assert!(r3.contains_str("0360"));
}
#[test]
fn test_padding_display() {
test_rs("001-010", "001-010", 10);
test_rs("00-02", "00-02", 3);
}
#[test]
fn test_empty() {
let rs = RangeSet::new();
assert!(rs.is_empty());
assert_eq!(rs.len(), 0);
assert_eq!(rs.to_string(), "");
}
#[test]
fn test_add_remove() {
let mut rs = RangeSet::new();
rs.add_int(5, 0);
rs.add_int(3, 0);
rs.add_int(1, 0);
assert_eq!(rs.len(), 3);
assert_eq!(rs.to_string(), "1,3,5");
rs.discard_str("3");
assert_eq!(rs.len(), 2);
assert_eq!(rs.to_string(), "1,5");
}
#[test]
fn test_intiter() {
let rs = RangeSet::parse("3,1,5,10", None).unwrap();
let vals: Vec<i64> = rs.intiter().collect();
assert_eq!(vals, vec![1, 3, 5, 10]);
}
#[test]
fn test_large_range() {
let rs = RangeSet::parse("1-1000", None).unwrap();
assert_eq!(rs.len(), 1000);
assert_eq!(rs.to_string(), "1-1000");
}
#[test]
fn test_diff_step() {
let mut r1 = RangeSet::parse("4-34/2", Some(3)).unwrap();
let r2 = RangeSet::parse("3-33/2", Some(3)).unwrap();
r1.difference_update(&r2);
assert_eq!(r1.to_string(), "4-34/2");
assert_eq!(r1.len(), 16);
let mut r1 = RangeSet::parse("4-34/2", Some(3)).unwrap();
let r2 = RangeSet::parse("2-14/2", Some(3)).unwrap();
r1.difference_update(&r2);
assert_eq!(r1.to_string(), "16-34/2");
assert_eq!(r1.len(), 10);
let mut r1 = RangeSet::parse("4-34/2", Some(3)).unwrap();
let r2 = RangeSet::parse("28-52/2", Some(3)).unwrap();
r1.difference_update(&r2);
assert_eq!(r1.to_string(), "4-26/2");
assert_eq!(r1.len(), 12);
let mut r1 = RangeSet::parse("4-34/2", Some(3)).unwrap();
let r2 = RangeSet::parse("12-18/2", Some(3)).unwrap();
r1.difference_update(&r2);
assert_eq!(r1.to_string(), "4-10/2,20-34/2");
assert_eq!(r1.len(), 12);
}
#[test]
fn test_diff_step_complex() {
let mut r1 = RangeSet::parse("1-100", Some(3)).unwrap();
let r2 = RangeSet::parse("2-98/2", Some(3)).unwrap();
r1.difference_update(&r2);
assert_eq!(r1.to_string(), "1-99/2,100");
assert_eq!(r1.len(), 51);
let mut r1 = RangeSet::parse("1-1000", Some(3)).unwrap();
let r2 = RangeSet::parse("2-999/2", Some(3)).unwrap();
r1.difference_update(&r2);
assert_eq!(r1.to_string(), "1-999/2,1000");
assert_eq!(r1.len(), 501);
}
#[test]
fn test_folding() {
let r1 = RangeSet::parse(
"112,114-117,119,121,130,132,134,136,138,139-141,144,147-148",
Some(6),
)
.unwrap();
assert_eq!(
r1.to_string(),
"112,114-117,119,121,130,132,134,136,138-141,144,147-148"
);
let r1 = RangeSet::parse(
"112,114-117,119,121,130,132,134,136,138,139-141,144,147-148",
Some(5),
)
.unwrap();
assert_eq!(
r1.to_string(),
"112,114-117,119,121,130-138/2,139-141,144,147-148"
);
let r1 = RangeSet::parse("1,3-4,6,8", None).unwrap();
assert_eq!(r1.to_string(), "1,3-4,6,8");
let r1 = RangeSet::parse("1,3-4,6,8", Some(4)).unwrap();
assert_eq!(r1.to_string(), "1,3-4,6,8");
let r1 = RangeSet::parse("1,3-4,6,8", Some(2)).unwrap();
assert_eq!(r1.to_string(), "1-3/2,4,6-8/2");
let r1 = RangeSet::parse("1,3-4,6,8", Some(3)).unwrap();
assert_eq!(r1.to_string(), "1,3-4,6,8");
}
#[test]
fn test_mixed_padding() {
let r0 = RangeSet::parse("030-031,032-100/2,101-489", Some(3)).unwrap();
assert_eq!(r0.to_string(), "030-032,034-100/2,101-489");
let r1 = RangeSet::parse("030-032,033-100/3,102", Some(3)).unwrap();
assert_eq!(r1.to_string(), "030-033,036-102/3");
let r2 = RangeSet::parse("030-032,033-100/3,101", Some(3)).unwrap();
assert_eq!(r2.to_string(), "030-033,036-099/3,101");
let r3 = RangeSet::parse("030-032,033-100/3,100", Some(3)).unwrap();
assert_eq!(r3.to_string(), "030-033,036-099/3,100");
}
#[test]
fn test_mixed_padding_with_different_widths() {
let r5 = RangeSet::parse("030-032,033-100/3,99-105/3,0001", Some(3)).unwrap();
assert_eq!(r5.to_string(), "99,030-033,036-105/3,0001");
}
#[test]
fn test_padding_mismatch_errors() {
assert!(RangeSet::parse("1-044", None).is_err());
assert!(RangeSet::parse("01-044", None).is_err());
assert!(RangeSet::parse("001-44", None).is_err());
assert!(RangeSet::parse("0-9,1-044", None).is_err());
assert!(RangeSet::parse("0-9,01-044", None).is_err());
assert!(RangeSet::parse("0-9,001-44", None).is_err());
assert!(RangeSet::parse("030-032,033-99/3,100", None).is_err());
}
#[test]
fn test_update_complex() {
let mut r1 = RangeSet::parse("1-100,102,105-242,800", None).unwrap();
assert_eq!(r1.len(), 240);
let r2 = RangeSet::parse("243-799,1924-1984", None).unwrap();
assert_eq!(r2.len(), 618);
r1.update(&r2);
assert_eq!(r1.len(), 240 + 618);
assert_eq!(r1.to_string(), "1-100,102,105-800,1924-1984");
}
#[test]
fn test_union_complex() {
let r1 = RangeSet::parse("1-100,102,105-242,800", None).unwrap();
let r2 = RangeSet::parse("243-799,1924-1984", None).unwrap();
let r3 = r1.union(&r2);
assert_eq!(r3.len(), 858);
assert_eq!(r3.to_string(), "1-100,102,105-800,1924-1984");
let r2 = RangeSet::parse("200-799", None).unwrap();
let r3 = r1.union(&r2);
assert_eq!(r3.len(), 797);
assert_eq!(r3.to_string(), "1-100,102,105-800");
}
#[test]
fn test_intersection_length() {
let r1 = RangeSet::parse("115-117,130,166-170,4780-4999", None).unwrap();
assert_eq!(r1.len(), 229);
let r2 = RangeSet::parse("116-117,130,4781-4999", None).unwrap();
assert_eq!(r2.len(), 222);
let res = r1.intersection(&r2);
assert_eq!(res.len(), 222);
let r1 = RangeSet::parse("115-200", None).unwrap();
assert_eq!(r1.len(), 86);
let r2 = RangeSet::parse("116-117,119,123-131,133,149,199", None).unwrap();
assert_eq!(r2.len(), 15);
let res = r1.intersection(&r2);
assert_eq!(res.len(), 15);
let r1 = RangeSet::parse("115-117,130,166-170,4780-4999,5003", None).unwrap();
assert_eq!(r1.len(), 230);
let r2 = RangeSet::parse("116-117,130,4781-4999", None).unwrap();
assert_eq!(r2.len(), 222);
let res = r1.intersection(&r2);
assert_eq!(res.len(), 222);
let r1 = RangeSet::parse("130,166-170,4780-4999", None).unwrap();
assert_eq!(r1.len(), 226);
let r2 = RangeSet::parse("116-117", None).unwrap();
assert_eq!(r2.len(), 2);
let res = r1.intersection(&r2);
assert_eq!(res.len(), 0);
}
#[test]
fn test_ior() {
let mut r1 = RangeSet::parse("1,3-9,14-21,30-39,42", None).unwrap();
let r2 = RangeSet::parse("2-5,10-32,35,40-41", None).unwrap();
r1.update(&r2);
assert_eq!(r1.len(), 42);
assert_eq!(r1.to_string(), "1-42");
}
#[test]
fn test_iand() {
let mut r1 = RangeSet::parse("1,3-9,14-21,30-39,42", None).unwrap();
let r2 = RangeSet::parse("2-5,10-32,35,40-41", None).unwrap();
r1.intersection_update(&r2);
assert_eq!(r1.len(), 15);
assert_eq!(r1.to_string(), "3-5,14-21,30-32,35");
}
#[test]
fn test_ixor() {
let mut r1 = RangeSet::parse("1,3-9,14-21,30-39,42", None).unwrap();
let r2 = RangeSet::parse("2-5,10-32,35,40-41", None).unwrap();
r1.symmetric_difference_update(&r2);
assert_eq!(r1.len(), 27);
assert_eq!(r1.to_string(), "1-2,6-13,22-29,33-34,36-42");
}
#[test]
fn test_isub() {
let mut r1 = RangeSet::parse("1,3-9,14-21,30-39,42", None).unwrap();
let r2 = RangeSet::parse("2-5,10-32,35,40-41", None).unwrap();
r1.difference_update(&r2);
assert_eq!(r1.len(), 12);
assert_eq!(r1.to_string(), "1,6-9,33-34,36-39,42");
}
#[test]
fn test_add_range_api() {
let mut r1 = RangeSet::new();
r1.add_range(1, 100, 1, 0);
assert_eq!(r1.len(), 99);
assert_eq!(r1.to_string(), "1-99");
r1.add_range(40, 101, 1, 0);
assert_eq!(r1.len(), 100);
assert_eq!(r1.to_string(), "1-100");
r1.add_range(399, 423, 2, 0);
assert_eq!(r1.len(), 112);
assert_eq!(
r1.to_string(),
"1-100,399,401,403,405,407,409,411,413,415,417,419,421"
);
let mut r1 = RangeSet::new();
r1.set_autostep(Some(3));
r1.add_range(1, 100, 1, 0);
assert_eq!(r1.autostep(), Some(3));
assert_eq!(r1.len(), 99);
assert_eq!(r1.to_string(), "1-99");
r1.add_range(40, 101, 1, 0);
assert_eq!(r1.len(), 100);
assert_eq!(r1.to_string(), "1-100");
r1.add_range(399, 423, 2, 0);
assert_eq!(r1.len(), 112);
assert_eq!(r1.to_string(), "1-100,399-421/2");
}
#[test]
fn test_add_range_bounds() {
let mut r1 = RangeSet::parse("1-30", Some(2)).unwrap();
assert_eq!(r1.len(), 30);
assert_eq!(r1.to_string(), "1-30");
r1.add_range(32, 35, 1, 0);
assert_eq!(r1.len(), 33);
assert_eq!(r1.to_string(), "1-30,32-34");
r1.add_range(31, 32, 1, 0);
assert_eq!(r1.len(), 34);
assert_eq!(r1.to_string(), "1-34");
let mut r1 = RangeSet::parse("1-30", Some(3)).unwrap();
r1.add_range(40, 65, 10, 0);
assert_eq!(r1.autostep(), Some(3));
assert_eq!(r1.len(), 33);
assert_eq!(r1.to_string(), "1-30,40-60/10");
r1.add_range(103, 104, 1, 0);
assert_eq!(r1.len(), 34);
assert_eq!(r1.to_string(), "1-30,40-60/10,103");
}
#[test]
fn test_autostep_property() {
let mut rs = RangeSet::new();
assert_eq!(rs.autostep(), None);
rs.set_autostep(Some(3));
assert_eq!(rs.autostep(), Some(3));
rs.set_autostep(None);
assert_eq!(rs.autostep(), None);
}
#[test]
fn test_padding_property() {
let r1 = RangeSet::parse("001-010", None).unwrap();
assert_eq!(r1.padding(), Some(3));
let r2 = RangeSet::parse("1-10", None).unwrap();
assert_eq!(r2.padding(), None);
let r3 = RangeSet::parse("0003-0143,0360-1000", None).unwrap();
assert_eq!(r3.padding(), Some(4));
}
#[test]
fn test_copy() {
let rangeset = RangeSet::parse("115-117,130,166-170,4780-4999", None).unwrap();
assert_eq!(rangeset.len(), 229);
assert_eq!(rangeset.to_string(), "115-117,130,166-170,4780-4999");
let mut r1 = rangeset.clone();
let mut r2 = rangeset.clone();
r1.remove_str("166");
assert_eq!(rangeset.len(), r1.len() + 1);
assert_eq!(rangeset.to_string(), "115-117,130,166-170,4780-4999");
assert_eq!(r1.to_string(), "115-117,130,167-170,4780-4999");
r2.update(&RangeSet::parse("118", None).unwrap());
assert_eq!(rangeset.len() + 1, r2.len());
assert_eq!(r2.to_string(), "115-118,130,166-170,4780-4999");
}
#[test]
fn test_remove_and_discard() {
let mut r1 = RangeSet::parse("1-100,102,105-242,800", None).unwrap();
assert_eq!(r1.len(), 240);
r1.remove_str("100");
assert_eq!(r1.len(), 239);
assert_eq!(r1.to_string(), "1-99,102,105-242,800");
r1.discard_str("101"); r1.discard_str("105");
assert_eq!(r1.len(), 238);
assert_eq!(r1.to_string(), "1-99,102,106-242,800");
}
#[test]
#[should_panic(expected = "not found")]
fn test_remove_missing_panics() {
let mut r1 = RangeSet::parse("1-100", None).unwrap();
r1.remove_str("101");
}
}