set version made and big progress on test generator

This commit is contained in:
ripytide 2022-11-24 21:46:20 +00:00
parent 73559b0e86
commit 0aec96e84d
7 changed files with 387 additions and 60 deletions

View File

@ -7,3 +7,5 @@ edition = "2021"
[dependencies]
either = "1.8.0"
pretty_trace = "0.5.23"
color-backtrace = "0.5.1"

View File

@ -1,4 +1,5 @@
use std::cmp::Ordering;
use std::ops::Bound;
pub enum StartBound<T> {
Included(T),
@ -36,12 +37,8 @@ where
{
pub fn cloned(&self) -> StartBound<T> {
match self {
StartBound::Included(point) => {
StartBound::Included((*point).clone())
}
StartBound::Excluded(point) => {
StartBound::Excluded((*point).clone())
}
StartBound::Included(point) => StartBound::Included((*point).clone()),
StartBound::Excluded(point) => StartBound::Excluded((*point).clone()),
StartBound::Unbounded => StartBound::Unbounded,
}
}
@ -95,6 +92,24 @@ impl<T> From<EndBound<T>> for StartBound<T> {
}
}
}
impl<T> From<Bound<T>> for StartBound<T> {
fn from(bound: Bound<T>) -> Self {
match bound {
Bound::Included(point) => StartBound::Included(point),
Bound::Excluded(point) => StartBound::Excluded(point),
Bound::Unbounded => StartBound::Unbounded,
}
}
}
impl<T> From<StartBound<T>> for Bound<T> {
fn from(start_bound: StartBound<T>) -> Bound<T> {
match start_bound {
StartBound::Included(point) => Bound::Included(point),
StartBound::Excluded(point) => Bound::Excluded(point),
StartBound::Unbounded => Bound::Unbounded,
}
}
}
pub enum EndBound<T> {
Included(T),
@ -145,7 +160,7 @@ where
{
fn eq(&self, other: &Self) -> bool {
match (self.inner(), other.inner()) {
(Some(start1), Some(start2)) => start1 == start2,
(Some(end1), Some(end2)) => end1 == end2,
(None, None) => true,
_ => false,
}
@ -161,9 +176,9 @@ where
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (self.inner(), other.inner()) {
//todo fix meh
(Some(start1), Some(start2)) => start1.partial_cmp(start2),
(None, Some(_)) => Some(Ordering::Less),
(Some(_), None) => Some(Ordering::Greater),
(Some(end1), Some(end2)) => end1.partial_cmp(end2),
(None, Some(_)) => Some(Ordering::Greater),
(Some(_), None) => Some(Ordering::Less),
(None, None) => Some(Ordering::Equal),
}
}
@ -179,11 +194,29 @@ where
}
impl<T> From<StartBound<T>> for EndBound<T> {
fn from(end_bound: StartBound<T>) -> Self {
match end_bound {
fn from(start_bound: StartBound<T>) -> Self {
match start_bound {
StartBound::Included(point) => EndBound::Included(point),
StartBound::Excluded(point) => EndBound::Excluded(point),
StartBound::Unbounded => EndBound::Unbounded,
}
}
}
impl<T> From<Bound<T>> for EndBound<T> {
fn from(bound: Bound<T>) -> Self {
match bound {
Bound::Included(point) => EndBound::Included(point),
Bound::Excluded(point) => EndBound::Excluded(point),
Bound::Unbounded => EndBound::Unbounded,
}
}
}
impl<T> From<EndBound<T>> for Bound<T> {
fn from(end_bound: EndBound<T>) -> Bound<T> {
match end_bound {
EndBound::Included(point) => Bound::Included(point),
EndBound::Excluded(point) => Bound::Excluded(point),
EndBound::Unbounded => Bound::Unbounded,
}
}
}

View File

@ -1,9 +1,10 @@
#![feature(is_some_and)]
pub mod bounds;
pub mod range_bounds;
pub mod range_bounds_map;
pub mod btree_ext;
pub mod overlapping_tests;
pub mod range_bounds;
pub mod range_bounds_map;
pub mod range_bounds_set;
pub use std::ops::RangeBounds as StdRangeBounds;
pub use std::ops::Bound as StdBound;
pub use crate::range_bounds_map::RangeBoundsMap;
pub use crate::range_bounds_set::RangeBoundsSet;

View File

@ -1,28 +1,75 @@
use std::ops::{Bound, Range};
#![feature(let_chains)]
use range_bounds_set::{range_bounds_set::RangeBoundsSet, range_bounds_ext::RangeBoundsExt};
use std::fmt::Display;
use std::ops::Bound;
use range_bounds_set::range_bounds::RangeBounds;
use range_bounds_set::RangeBoundsSet;
static NICE_NUMBERS: &'static [u8] = &[2, 4, 6, 8, 10];
type Sim = (Bound<u8>, Bound<u8>);
type TestBounds = (Bound<u8>, Bound<u8>);
fn main() {
println!("Hello, world!");
//pretty_trace::PrettyTrace::new().on();
color_backtrace::install();
for test_case in generate_overlap_test_cases() {
println!("{}", test_case);
}
}
struct OverlapTestCase {
range_bounds_set: RangeBoundsSet<Sim, u8>,
overlap_range: Sim,
range_bounds_set: RangeBoundsSet<u8, TestBounds>,
overlap_range: TestBounds,
}
impl Display for OverlapTestCase {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let range_bounds_iterator = self.range_bounds_set.iter();
writeln!(f, "=== 1 2 3 4 5 6 7 8 9 10 ===")?;
for range_bounds in range_bounds_iterator {
writeln!(f, "{}", display_test_bounds(range_bounds))?;
}
writeln!(f)?;
writeln!(f, "Overlapping:")?;
writeln!(f, "{}", display_test_bounds(&self.overlap_range))?;
Ok(())
}
}
fn display_test_bounds(test_bounds: &TestBounds) -> String {
let first_symbol_position = inner(&test_bounds.0).unwrap_or(&0);
let second_symbol_position = inner(&test_bounds.1).unwrap_or(&16);
format!(
"{}{}{}{}",
" ".repeat(*first_symbol_position as usize),
bound_symbol(&test_bounds.0),
"-".repeat(*second_symbol_position as usize),
bound_symbol(&test_bounds.1)
)
}
fn bound_symbol(bound: &Bound<u8>) -> String {
match bound {
Bound::Included(_) => "".to_string(),
Bound::Excluded(_) => "".to_string(),
Bound::Unbounded => "".to_string(),
}
}
struct OverlapTestCaseWithAnswer {
test_case: OverlapTestCase,
answer: Vec<Sim>,
answer: Vec<TestBounds>,
}
fn generate_overlap_test_cases() -> Vec<OverlapTestCase> {
let mut output = Vec::new();
//case zero
for overlap_range in all_sim() {
for overlap_range in all_valid_test_bounds() {
output.push(OverlapTestCase {
range_bounds_set: RangeBoundsSet::new(),
overlap_range,
@ -30,10 +77,10 @@ fn generate_overlap_test_cases() -> Vec<OverlapTestCase> {
}
//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);
for overlap_range in all_valid_test_bounds() {
for inside_range in all_valid_test_bounds() {
let mut range_bounds_set = range_bounds_set::RangeBoundsSet::new();
range_bounds_set.insert(inside_range).unwrap();
output.push(OverlapTestCase {
range_bounds_set,
overlap_range,
@ -42,34 +89,43 @@ fn generate_overlap_test_cases() -> Vec<OverlapTestCase> {
}
//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));
for overlap_range in all_valid_test_bounds() {
for (test_bounds1, test_bounds2) in all_valid_test_bounds_pairs() {
let mut range_bounds_set = range_bounds_set::RangeBoundsSet::new();
range_bounds_set.insert(test_bounds1).unwrap();
dbg!(test_bounds2);
range_bounds_set.insert(test_bounds2).unwrap();
output.push(OverlapTestCase {
range_bounds_set,
overlap_range,
})
}
}
output.retain(is_valid_sim_pair);
return output;
}
fn all_valid_test_bounds_pairs() -> Vec<(TestBounds, TestBounds)> {
let mut output = Vec::new();
for test_bounds1 in all_valid_test_bounds() {
for test_bounds2 in all_valid_test_bounds() {
output.push((test_bounds1, test_bounds2));
}
}
output.retain(is_valid_test_bounds_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 is_valid_test_bounds_pair(
(test_bounds1, test_bounds2): &(TestBounds, TestBounds),
) -> bool {
//do they overlap?
!test_bounds1.overlaps(test_bounds2)
}
fn all_sim() -> Vec<Sim> {
fn all_valid_test_bounds() -> Vec<TestBounds> {
let mut output = Vec::new();
//bounded-bounded
@ -88,9 +144,33 @@ fn all_sim() -> Vec<Sim> {
}
//bounded-bounded
output.push((Bound::Unbounded, Bound::Unbounded));
output.retain(is_valid_test_bounds);
return output;
}
fn is_valid_test_bounds(test_bounds: &TestBounds) -> bool {
//the one exception for zero ranges
if let Bound::Included(start) = test_bounds.0 && let Bound::Included(end) = test_bounds.1 && start==end {
return true;
}
match inner(&test_bounds.0) {
Some(start) => match inner(&test_bounds.1) {
Some(end) => start < end,
None => true,
},
None => true,
}
}
fn inner(bound: &Bound<u8>) -> Option<&u8> {
match bound {
Bound::Included(point) => Some(point),
Bound::Excluded(point) => Some(point),
Bound::Unbounded => None,
}
}
fn all_finite_bounded() -> Vec<Bound<u8>> {
let mut output = Vec::new();
for i in 0..5 {

View File

@ -6,10 +6,11 @@ where
{
fn start_bound(&self) -> StartBound<&T>;
fn end_bound(&self) -> EndBound<&T>;
fn dummy(start_bound: StartBound<T>, end_bound: EndBound<T>) -> Self;
fn get_pair(&self) -> (StartBound<&T>, EndBound<&T>) {
(self.start_bound(), self.end_bound())
}
fn dummy(start_bound: StartBound<T>, end_bound: EndBound<T>) -> Self;
fn contains(&self, item: &T) -> bool {
(match self.start_bound() {
StartBound::Included(start) => start <= item,
@ -58,3 +59,165 @@ where
|| same_exclusive
}
}
use std::ops::{
Bound, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo,
RangeToInclusive,
};
impl<T> RangeBounds<T> for (Bound<T>, Bound<T>)
where
T: PartialOrd,
{
//todo use Froms and AsRef stuff and functions to do this instead of bare
//matching
fn start_bound(&self) -> StartBound<&T> {
match self.0 {
Bound::Included(ref point) => StartBound::Included(point),
Bound::Excluded(ref point) => StartBound::Excluded(point),
Bound::Unbounded => StartBound::Unbounded,
}
}
fn end_bound(&self) -> EndBound<&T> {
match self.1 {
Bound::Included(ref point) => EndBound::Included(point),
Bound::Excluded(ref point) => EndBound::Excluded(point),
Bound::Unbounded => EndBound::Unbounded,
}
}
fn dummy(start_bound: StartBound<T>, end_bound: EndBound<T>) -> Self {
(Bound::from(start_bound), Bound::from(end_bound))
}
}
impl<T> RangeBounds<T> for Range<T>
where
T: PartialOrd,
{
fn start_bound(&self) -> StartBound<&T> {
StartBound::Included(&self.start)
}
fn end_bound(&self) -> EndBound<&T> {
EndBound::Excluded(&self.end)
}
fn dummy(start_bound: StartBound<T>, end_bound: EndBound<T>) -> Self {
if let StartBound::Included(start) = start_bound {
if let EndBound::Excluded(end) = end_bound {
return Range { start, end };
} else {
panic!("The end of a Range must be Excluded(_)")
}
} else {
panic!("The start of a Range must be Included(_)")
}
}
}
impl<T> RangeBounds<T> for RangeFrom<T>
where
T: PartialOrd,
{
fn start_bound(&self) -> StartBound<&T> {
StartBound::Included(&self.start)
}
fn end_bound(&self) -> EndBound<&T> {
EndBound::Unbounded
}
fn dummy(start_bound: StartBound<T>, end_bound: EndBound<T>) -> Self {
if let StartBound::Included(start) = start_bound {
if let EndBound::Unbounded = end_bound {
return RangeFrom { start };
} else {
panic!("The end of a RangeFrom must be Unbounded")
}
} else {
panic!("The start of a RangeFrom must be Included(_)")
}
}
}
impl<T> RangeBounds<T> for RangeFull
where
T: PartialOrd,
{
fn start_bound(&self) -> StartBound<&T> {
StartBound::Unbounded
}
fn end_bound(&self) -> EndBound<&T> {
EndBound::Unbounded
}
fn dummy(start_bound: StartBound<T>, end_bound: EndBound<T>) -> Self {
if let StartBound::Unbounded = start_bound {
if let EndBound::Unbounded = end_bound {
return RangeFull {};
} else {
panic!("The end of a RangeFull must be Unbounded")
}
} else {
panic!("The start of a RangeFull must be Unbounded")
}
}
}
impl<T> RangeBounds<T> for RangeInclusive<T>
where
T: PartialOrd,
{
fn start_bound(&self) -> StartBound<&T> {
StartBound::Included(self.start())
}
fn end_bound(&self) -> EndBound<&T> {
EndBound::Included(self.end())
}
fn dummy(start_bound: StartBound<T>, end_bound: EndBound<T>) -> Self {
if let StartBound::Included(start) = start_bound {
if let EndBound::Included(end) = end_bound {
return RangeInclusive::new(start, end);
} else {
panic!("The end of a RangeInclusive must be Included(_)")
}
} else {
panic!("The start of a RangeInclusive must be Included(_)")
}
}
}
impl<T> RangeBounds<T> for RangeTo<T>
where
T: PartialOrd,
{
fn start_bound(&self) -> StartBound<&T> {
StartBound::Unbounded
}
fn end_bound(&self) -> EndBound<&T> {
EndBound::Excluded(&self.end)
}
fn dummy(start_bound: StartBound<T>, end_bound: EndBound<T>) -> Self {
if let StartBound::Unbounded = start_bound {
if let EndBound::Excluded(end) = end_bound {
return RangeTo { end };
} else {
panic!("The end of a RangeTo must be Excluded(_)")
}
} else {
panic!("The start of a RangeTo must be Unbounded")
}
}
}
impl<T> RangeBounds<T> for RangeToInclusive<T>
where
T: PartialOrd,
{
fn start_bound(&self) -> StartBound<&T> {
StartBound::Unbounded
}
fn end_bound(&self) -> EndBound<&T> {
EndBound::Included(&self.end)
}
fn dummy(start_bound: StartBound<T>, end_bound: EndBound<T>) -> Self {
if let StartBound::Unbounded = start_bound {
if let EndBound::Included(end) = end_bound {
return RangeToInclusive { end };
} else {
panic!("The end of a RangeToInclusive must be Included(_)")
}
} else {
panic!("The start of a RangeToInclusive must be Unbounded")
}
}
}

View File

@ -1,15 +1,13 @@
use std::collections::BTreeMap;
use std::iter::once;
use std::ops::Bound;
use either::Either;
use crate::bounds::{EndBound, StartBound};
use crate::btree_ext::BTreeMapExt;
use crate::range_bounds::RangeBounds;
use crate::StdBound;
//todo switch to slot map thingy
#[derive(Default)]
pub struct RangeBoundsMap<I, K, V> {
starts: BTreeMap<StartBound<I>, (K, V)>,
}
@ -32,12 +30,18 @@ where
return Err(());
}
//todo panic on invalid inputs
self.starts
.insert(range_bounds.start_bound().cloned(), (range_bounds, value));
return Ok(());
}
pub fn contains_point(&self, point: &I) -> bool {
self.get(point).is_some()
}
pub fn overlaps(&self, search_range_bounds: &K) -> bool {
self.overlapping(search_range_bounds).next().is_some()
}
@ -45,12 +49,11 @@ where
pub fn overlapping(
&self,
search_range_bounds: &K,
) -> Either<impl Iterator<Item = (&K, &V)>, impl Iterator<Item = (&K, &V)>>
{
) -> impl Iterator<Item = (&K, &V)> {
let start_range_bounds = (
//Included is lossless regarding meta-bounds searches
StdBound::Included(search_range_bounds.start_bound().cloned()),
StdBound::Included(StartBound::from(
Bound::Included(search_range_bounds.start_bound().cloned()),
Bound::Included(StartBound::from(
search_range_bounds.end_bound().cloned(),
)),
);
@ -62,7 +65,7 @@ where
//Excluded is lossless regarding meta-bounds searches
//because we don't want equal bound as they would have be
//coverded in the previous step
self.starts.next_below_upper_bound(StdBound::Excluded(
self.starts.next_below_upper_bound(Bound::Excluded(
//optimisation fix this without cloning
&search_range_bounds.start_bound().cloned(),
)) {
@ -107,10 +110,6 @@ where
return None;
}
pub fn contains_point(&self, point: &I) -> bool {
self.get(point).is_some()
}
pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> {
self.starts.iter().map(|(_, (key, value))| (key, value))
}

View File

@ -0,0 +1,49 @@
use crate::range_bounds::RangeBounds;
use crate::range_bounds_map::RangeBoundsMap;
pub struct RangeBoundsSet<I, K> {
map: RangeBoundsMap<I, K, ()>,
}
impl<I, K> RangeBoundsSet<I, K>
where
K: RangeBounds<I>,
I: Ord + Clone,
{
pub fn new() -> Self {
RangeBoundsSet {
map: RangeBoundsMap::new(),
}
}
//returns Err(()) if the given range overlaps another range
//does not coalesce ranges if they touch
pub fn insert(&mut self, range_bounds: K) -> Result<(), ()> {
self.map.insert(range_bounds, ())
}
pub fn overlaps(&self, search_range_bounds: &K) -> bool {
self.map.overlaps(search_range_bounds)
}
pub fn overlapping(
&self,
search_range_bounds: &K,
) -> impl Iterator<Item = &K> {
self.map
.overlapping(search_range_bounds)
.map(|(key, _)| key)
}
pub fn get(&self, point: &I) -> Option<&K> {
self.map.get_key_value(point).map(|(key, _)| key)
}
pub fn contains_point(&self, point: &I) -> bool {
self.map.contains_point(point)
}
pub fn iter(&self) -> impl Iterator<Item = &K> {
self.map.iter().map(|(key, _)| key)
}
}