should probaly commit it's been a few hours lol
This commit is contained in:
commit
9154cca2a5
9
range_bounds_set/Cargo.toml
Normal file
9
range_bounds_set/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "range_bounds_set"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
derive-new = "0.5"
|
23
range_bounds_set/src/bound_ext.rs
Normal file
23
range_bounds_set/src/bound_ext.rs
Normal file
@ -0,0 +1,23 @@
|
||||
use std::ops::Bound;
|
||||
|
||||
pub trait BoundExt<T> {
|
||||
fn inner(&self) -> Option<&T>;
|
||||
fn is_unbounded(&self) -> bool;
|
||||
}
|
||||
|
||||
impl<T> BoundExt<T> for Bound<T> {
|
||||
fn inner(&self) -> Option<&T> {
|
||||
match self {
|
||||
Bound::Included(inner) => Some(inner),
|
||||
Bound::Excluded(inner) => Some(inner),
|
||||
Bound::Unbounded => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_unbounded(&self) -> bool {
|
||||
match self {
|
||||
Bound::Unbounded => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
5
range_bounds_set/src/lib.rs
Normal file
5
range_bounds_set/src/lib.rs
Normal file
@ -0,0 +1,5 @@
|
||||
#![feature(is_some_and)]
|
||||
pub mod bound_ext;
|
||||
pub mod range_bounds_ext;
|
||||
pub mod range_bounds_set;
|
||||
pub mod specific_bounds;
|
109
range_bounds_set/src/main.rs
Normal file
109
range_bounds_set/src/main.rs
Normal file
@ -0,0 +1,109 @@
|
||||
use std::ops::{Bound, Range};
|
||||
|
||||
use range_bounds_set::{range_bounds_set::RangeBoundsSet, range_bounds_ext::RangeBoundsExt};
|
||||
|
||||
static NICE_NUMBERS: &'static [u8] = &[2, 4, 6, 8, 10];
|
||||
type Sim = (Bound<u8>, Bound<u8>);
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
|
||||
struct OverlapTestCase {
|
||||
range_bounds_set: RangeBoundsSet<Sim, u8>,
|
||||
overlap_range: Sim,
|
||||
}
|
||||
|
||||
struct OverlapTestCaseWithAnswer {
|
||||
test_case: OverlapTestCase,
|
||||
answer: Vec<Sim>,
|
||||
}
|
||||
|
||||
fn generate_overlap_test_cases() -> Vec<OverlapTestCase> {
|
||||
let mut output = Vec::new();
|
||||
//case zero
|
||||
for overlap_range in all_sim() {
|
||||
output.push(OverlapTestCase {
|
||||
range_bounds_set: RangeBoundsSet::new(),
|
||||
overlap_range,
|
||||
})
|
||||
}
|
||||
|
||||
//case one
|
||||
for overlap_range in all_sim() {
|
||||
for inside_range in all_sim() {
|
||||
let mut range_bounds_set = RangeBoundsSet::new();
|
||||
range_bounds_set.raw_insert(inside_range);
|
||||
output.push(OverlapTestCase {
|
||||
range_bounds_set,
|
||||
overlap_range,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//case two
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
fn all_valid_sim_pairs() -> Vec<(Sim, Sim)> {
|
||||
let mut output = Vec::new();
|
||||
for sim1 in all_sim() {
|
||||
for sim2 in all_sim() {
|
||||
output.push((sim1, sim2));
|
||||
}
|
||||
}
|
||||
|
||||
output.retain(is_valid_sim_pair);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
fn is_valid_sim_pair((sim1, sim2): &(Sim, Sim)) -> bool {
|
||||
//do they overlap?
|
||||
if sim1.overlaps(sim2) {
|
||||
return false;
|
||||
}
|
||||
if
|
||||
|
||||
//is it an exclusive-exclusive with start==end?
|
||||
}
|
||||
|
||||
fn all_sim() -> Vec<Sim> {
|
||||
let mut output = Vec::new();
|
||||
|
||||
//bounded-bounded
|
||||
for start_bound in all_finite_bounded() {
|
||||
for end_bound in all_finite_bounded() {
|
||||
output.push((start_bound, end_bound));
|
||||
}
|
||||
}
|
||||
//bounded-unbounded
|
||||
for start_bound in all_finite_bounded() {
|
||||
output.push((start_bound, Bound::Unbounded));
|
||||
}
|
||||
//unbounded-bounded
|
||||
for end_bound in all_finite_bounded() {
|
||||
output.push((Bound::Unbounded, end_bound));
|
||||
}
|
||||
//bounded-bounded
|
||||
output.push((Bound::Unbounded, Bound::Unbounded));
|
||||
return output;
|
||||
}
|
||||
|
||||
fn all_finite_bounded() -> Vec<Bound<u8>> {
|
||||
let mut output = Vec::new();
|
||||
for i in 0..5 {
|
||||
for k in 0..=1 {
|
||||
output.push(finite_bound(i, k == 0));
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
fn finite_bound(x: u8, included: bool) -> Bound<u8> {
|
||||
match included {
|
||||
true => Bound::Included(x),
|
||||
false => Bound::Excluded(x),
|
||||
}
|
||||
}
|
54
range_bounds_set/src/range_bounds_ext.rs
Normal file
54
range_bounds_set/src/range_bounds_ext.rs
Normal file
@ -0,0 +1,54 @@
|
||||
use std::ops::{Bound, RangeBounds};
|
||||
|
||||
use crate::bound_ext::BoundExt;
|
||||
|
||||
pub trait RangeBoundsExt<T> {
|
||||
fn overlaps(&self, other: &Self) -> bool;
|
||||
fn get_pair(&self) -> (Bound<&T>, Bound<&T>);
|
||||
}
|
||||
|
||||
impl<T, K> RangeBoundsExt<T> for K
|
||||
where
|
||||
K: RangeBounds<T>,
|
||||
T: PartialOrd,
|
||||
{
|
||||
fn get_pair(&self) -> (Bound<&T>, Bound<&T>) {
|
||||
(self.start_bound(), self.end_bound())
|
||||
}
|
||||
fn overlaps(&self, other: &Self) -> bool {
|
||||
let self_start_contained = self
|
||||
.start_bound()
|
||||
.inner()
|
||||
.is_some_and(|start| other.contains(*start));
|
||||
let self_end_contained = self
|
||||
.end_bound()
|
||||
.inner()
|
||||
.is_some_and(|end| other.contains(*end));
|
||||
let other_start_contained = other
|
||||
.start_bound()
|
||||
.inner()
|
||||
.is_some_and(|start| self.contains(*start));
|
||||
let other_end_contained = other
|
||||
.end_bound()
|
||||
.inner()
|
||||
.is_some_and(|end| self.contains(*end));
|
||||
let double_unbounded = self.start_bound().is_unbounded()
|
||||
&& self.end_bound().is_unbounded()
|
||||
&& other.start_bound().is_unbounded()
|
||||
&& other.end_bound().is_unbounded();
|
||||
let same_exclusive = match (self.get_pair(), other.get_pair()) {
|
||||
(
|
||||
(Bound::Excluded(start1), Bound::Excluded(end1)),
|
||||
(Bound::Excluded(start2), Bound::Excluded(end2)),
|
||||
) if start1 == start2 && end1 == end2 => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
self_start_contained
|
||||
|| self_end_contained
|
||||
|| other_start_contained
|
||||
|| other_end_contained
|
||||
|| double_unbounded
|
||||
|| same_exclusive
|
||||
}
|
||||
}
|
69
range_bounds_set/src/range_bounds_set.rs
Normal file
69
range_bounds_set/src/range_bounds_set.rs
Normal file
@ -0,0 +1,69 @@
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Bound, RangeBounds};
|
||||
|
||||
use derive_new::new;
|
||||
|
||||
use crate::bound_ext::{EndBoundWithOrd, StartBoundWithOrd};
|
||||
|
||||
type Id = u128;
|
||||
|
||||
//todo switch to slot map thingy
|
||||
#[derive(Default, new)]
|
||||
pub struct RangeBoundsSet<T, I> {
|
||||
#[new(default)]
|
||||
ranges: HashMap<Id, T>,
|
||||
#[new(default)]
|
||||
starts: BTreeSet<StartBoundWithOrd<I>>,
|
||||
#[new(default)]
|
||||
ends: BTreeSet<EndBoundWithOrd<I>>,
|
||||
phantom_data: PhantomData<I>,
|
||||
|
||||
#[new(default)]
|
||||
id: u128,
|
||||
}
|
||||
|
||||
impl<T, I> RangeBoundsSet<T, I>
|
||||
where
|
||||
T: RangeBounds<I>,
|
||||
I: Ord,
|
||||
{
|
||||
//returns Err(()) if the inserting the given range overlaps another range
|
||||
//coalesces ranges if they touch
|
||||
pub fn insert(&mut self, range: T) -> Result<(), ()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn raw_insert(&mut self, range: T) {}
|
||||
|
||||
pub fn overlapping(&self, range: T) {
|
||||
self.ends.range(range);
|
||||
}
|
||||
|
||||
pub fn get(&self, point: &I) {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
//use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
// So there are a lot of permutations for overlaps checks: like 100's even
|
||||
// for less than 3 ranges inside the see my picture in
|
||||
// notes/ for an idea
|
||||
// Hence the strategy since I want thorough testing at least for
|
||||
// T = { 0, 1, 2 } where T is the number of ranges in the rangeset
|
||||
// upon query, and I want every valid (maintains invariant of no
|
||||
// overlaps (only relevant for T=2)) permutation of query to
|
||||
// interval set to have it's own test.
|
||||
//
|
||||
// This strategy is open-ended if anyone feels like manually
|
||||
// inputing the T=3 cases ;p
|
||||
//
|
||||
// And so rather than figuring all the valid cases manually I
|
||||
// wrote a script to do it for me, and then I also wrote a helper
|
||||
// script to streamline the manual input process. The script
|
||||
// essentially enumerates all of the generated cases and asks me
|
||||
// to input the expected
|
||||
}
|
103
range_bounds_set/src/specific_bounds.rs
Normal file
103
range_bounds_set/src/specific_bounds.rs
Normal file
@ -0,0 +1,103 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use crate::bound_ext::BoundExt;
|
||||
|
||||
pub enum StartBound<T> {
|
||||
Included(T),
|
||||
Excluded(T),
|
||||
Unbounded,
|
||||
}
|
||||
|
||||
impl<T> PartialEq for StartBound<T>
|
||||
where
|
||||
T: PartialEq,
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self.inner(), other.inner()) {
|
||||
(Some(start1), Some(start2)) => start1 == start2,
|
||||
(None, None) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PartialOrd for StartBound<T>
|
||||
where
|
||||
T: PartialOrd,
|
||||
{
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
match (self.inner(), other.inner()) {
|
||||
(Some(start1), Some(start2)) => start1.partial_cmp(start2),
|
||||
(None, Some(_)) => Some(Ordering::Less),
|
||||
(Some(_), None) => Some(Ordering::Greater),
|
||||
(None, None) => Some(Ordering::Equal),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> BoundExt<T> for StartBound<T> {
|
||||
fn inner(&self) -> Option<&T> {
|
||||
match self {
|
||||
StartBound::Included(inner) => Some(inner),
|
||||
StartBound::Excluded(inner) => Some(inner),
|
||||
StartBound::Unbounded => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_unbounded(&self) -> bool {
|
||||
match self {
|
||||
StartBound::Unbounded => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum EndBound<T> {
|
||||
Included(T),
|
||||
Excluded(T),
|
||||
Unbounded,
|
||||
}
|
||||
|
||||
impl<T> PartialEq for EndBound<T>
|
||||
where
|
||||
T: PartialEq,
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self.inner(), other.inner()) {
|
||||
(Some(start1), Some(start2)) => start1 == start2,
|
||||
(None, None) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PartialOrd for EndBound<T>
|
||||
where
|
||||
T: PartialOrd,
|
||||
{
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
match (self.inner(), other.inner()) {
|
||||
(Some(start1), Some(start2)) => start1.partial_cmp(start2),
|
||||
(None, Some(_)) => Some(Ordering::Less),
|
||||
(Some(_), None) => Some(Ordering::Greater),
|
||||
(None, None) => Some(Ordering::Equal),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> BoundExt<T> for EndBound<T> {
|
||||
fn inner(&self) -> Option<&T> {
|
||||
match self {
|
||||
EndBound::Included(inner) => Some(inner),
|
||||
EndBound::Excluded(inner) => Some(inner),
|
||||
EndBound::Unbounded => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_unbounded(&self) -> bool {
|
||||
match self {
|
||||
EndBound::Unbounded => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user