Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev13 #22

Merged
merged 17 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,53 @@ jobs:
- name: Run test suite
# The `riscv32i` build is needed to actually detect if the crate is no_std.
# The `-p triple_arena` builds are so that the testcrate isn't always activating flags
# Note that the test crate has a serde_support flag
run: |
cargo b --target=riscv32i-unknown-none-elf -p no_std_test
cargo b --no-default-features -p triple_arena
cargo b --no-default-features --features=serde -p triple_arena
cargo b --no-default-features --features=expose_internal_utils -p triple_arena
cargo b --no-default-features
cargo b --all-features
cargo t --no-default-features
cargo t --all-features
cargo t --release --all-features
cargo r --bin render0
cargo r --bin render1
cargo r --example equation

miri:
name: Miri
runs-on: ubuntu-latest
# note: we have turned on this Miri flag
env:
RUSTFLAGS: -D warnings
MIRIFLAGS: -Zmiri-tree-borrows -Zmiri-strict-provenance
steps:
- uses: actions/checkout@v2
- name: Install most recent Miri
run: |
rustup set profile minimal
rustup default "nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri)"
rustup component add miri
- name: Run test suite with Miri
run: |
cargo miri test

msrv_test_suite:
runs-on: ubuntu-latest
env:
RUSTFLAGS: -D warnings
steps:
- uses: actions/checkout@v2
- name: Install Rust components
run: |
rustup set profile minimal
rustup install nightly-2023-04-14
- name: Run test suite
run: |
cargo build --no-default-features

rustfmt:
name: Rustfmt
runs-on: ubuntu-latest
Expand Down Expand Up @@ -62,3 +96,4 @@ jobs:
- name: Run `cargo clippy`
run: |
cargo clippy --all --all-targets --all-features -- -D clippy::all
cargo clippy --all --all-targets --no-default-features -- -D clippy::all
7 changes: 6 additions & 1 deletion testcrate/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,10 @@ postcard = { version = "1.0", features = ["alloc"] }
rand_xoshiro = "0.6"
serde = "1.0"
serde_derive = "1.0"
triple_arena = { path = "../triple_arena", features = ["expose_internal_utils", "serde_support"] }
triple_arena = { path = "../triple_arena", features = ["expose_internal_utils"] }
triple_arena_render = { path = "../triple_arena_render" }

# separate feature because we need to test the `ptr_struct` macro both ways
[features]
default = ["serde_support"]
serde_support = ["triple_arena/serde_support"]
59 changes: 31 additions & 28 deletions testcrate/src/bin/render1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,39 +12,42 @@ fn main() {
let mut rng = Xoshiro128StarStar::seed_from_u64(1);
let mut a: Arena<P0, MyNode<P0>> = Arena::new();
let mut ptrs = vec![];
for i in 0..100 {
let mut node = MyNode::new(vec![], vec![], vec![]);
if (rng.next_u32() % 8) != 0 {
node.center.push(format!("n{}", i))
}
loop {
if (rng.next_u32() % 8) == 0 {
node.center.push("center".to_string());
} else {
break
for _ in 0..100 {
a.insert_with(|p| {
let mut node = MyNode::new(vec![], vec![], vec![]);
if (rng.next_u32() % 8) != 0 {
node.center.push(format!("{}", p))
}
}
loop {
if (rng.next_u32() % 4) == 0 {
if !ptrs.is_empty() {
let inx = (rng.next_u32() as usize) % ptrs.len();
node.sources.push((ptrs[inx], format!("p{}", inx)));
loop {
if (rng.next_u32() % 8) == 0 {
node.center.push("center".to_string());
} else {
break
}
} else {
break
}
}
loop {
if (rng.next_u32() % 4) == 0 {
if !ptrs.is_empty() {
let inx = (rng.next_u32() as usize) % ptrs.len();
node.sinks.push((ptrs[inx], format!("p{}", inx)));
loop {
if (rng.next_u32() % 4) == 0 {
if !ptrs.is_empty() {
let inx = (rng.next_u32() as usize) % ptrs.len();
node.sources.push((ptrs[inx], format!("p{}", inx)));
}
} else {
break
}
} else {
break
}
}
ptrs.push(a.insert(node))
loop {
if (rng.next_u32() % 4) == 0 {
if !ptrs.is_empty() {
let inx = (rng.next_u32() as usize) % ptrs.len();
node.sinks.push((ptrs[inx], format!("p{}", inx)));
}
} else {
break
}
}
ptrs.push(p);
node
});
}

render_to_svg_file(
Expand Down
10 changes: 5 additions & 5 deletions testcrate/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ ptr_struct!(P0[NonZeroU32](NonZeroU128));
ptr_struct!(P1);

thread_local! {
pub static CLONE_COUNT: RefCell<u64> = RefCell::new(0);
pub static CMP_COUNT: RefCell<u64> = RefCell::new(0);
pub static VAL_NUM: RefCell<u64> = RefCell::new(0);
pub static SEED: RefCell<u64> = RefCell::new(0);
pub static CLONE_COUNT: RefCell<u64> = const { RefCell::new(0) };
pub static CMP_COUNT: RefCell<u64> = const { RefCell::new(0) };
pub static VAL_NUM: RefCell<u64> = const { RefCell::new(0) };
pub static SEED: RefCell<u64> = const { RefCell::new(0) };
}

pub fn get_next_seed() -> u64 {
Expand Down Expand Up @@ -115,7 +115,7 @@ impl PartialEq for CKey {
}
}

#[allow(clippy::incorrect_partial_ord_impl_on_ord_type)]
#[allow(clippy::non_canonical_partial_ord_impl)]
impl PartialOrd for CKey {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
inc_cmp_count();
Expand Down
68 changes: 57 additions & 11 deletions testcrate/tests/fuzz_ord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ const N: usize = if cfg!(miri) {
};

const STATS: (usize, u64, u128) = if cfg!(miri) {
(70, 1, 122)
(69, 1, 122)
} else if cfg!(debug_assertions) {
(239, 107, 14567)
(223, 107, 14569)
} else {
(418, 5049, 749771)
(420, 5049, 749789)
};

macro_rules! next_inx {
Expand Down Expand Up @@ -411,7 +411,42 @@ fn fuzz_ord() {
assert!(a.find_with(|_, k, _| new_k.cmp(k)).is_none());
}
}
550..=994 => {
550..=579 => {
// find_similar_with
let new_k = new_k();
if let Some(set) = b.get(&new_k) {
let (p, ord) = a
.find_similar_with(|p, k, v| {
assert_eq!(a.get(p).unwrap(), (k, v));
new_k.cmp(k)
})
.unwrap();
let v = *a.get_val(p).unwrap();
assert!(set.contains_key(&v));
assert_eq!(ord, Ordering::Equal);
} else if a.is_empty() {
assert!(a.find_similar_with(|_, k, _| new_k.cmp(k)).is_none());
} else {
let (p, ord) = a.find_similar_with(|_, k, _| new_k.cmp(k)).unwrap();
let k = *a.get_key(p).unwrap();
match ord {
Ordering::Less => {
if let Some(prev) = a.get_link(p).unwrap().prev() {
assert!(*a.get_key(prev).unwrap() < new_k);
}
assert!(new_k < k);
}
Ordering::Equal => unreachable!(),
Ordering::Greater => {
if let Some(next) = a.get_link(p).unwrap().next() {
assert!(new_k < *a.get_key(next).unwrap());
}
assert!(k < new_k);
}
}
}
}
580..=994 => {
// find_key with get_val
let new_k = new_k();
if let Some(set) = b.get(&new_k) {
Expand All @@ -423,41 +458,52 @@ fn fuzz_ord() {
}
}
995 => {
// advancer, ptrs, iter, keys, keys_mut, vals, vals_mut
// advancer, ptrs, iter, keys, keys_mut, vals, vals_mut, advancer_starting_from
let mut adv = a.advancer();
let mut ptrs = a.ptrs();
let mut iter = a.iter();
let mut keys = a.keys();
let mut vals = a.vals();
let new_k = new_k();
let p_start = a.find_key(&new_k).unwrap_or(Ptr::invalid());
let mut adv_from = a.advancer_starting_from(p_start);
let mut adv_from_started = false;
while let Some(p) = adv.advance(&a) {
let (k, v) = a.get(p).unwrap();
assert_eq!(ptrs.next().unwrap(), p);
assert_eq!(iter.next().unwrap(), (p, k, v));
assert_eq!(*keys.next().unwrap(), *k);
assert_eq!(*vals.next().unwrap(), *v);
if p_start == p {
adv_from_started = true;
}
if adv_from_started {
assert_eq!(adv_from.advance(&a).unwrap(), p);
}
}
assert!(adv_from.advance(&a).is_none());
for v in a.vals_mut() {
black_box(v);
}
}
996 => {
// min
// first
if len != 0 {
let set = b.first_entry().unwrap();
let v = a.get_val(a.min().unwrap()).unwrap();
let v = a.get_val(a.first().unwrap()).unwrap();
assert!(set.get().contains_key(v));
} else {
assert!(a.min().is_none());
assert!(a.first().is_none());
}
}
997 => {
// max
// last
if len != 0 {
let set = b.last_entry().unwrap();
let v = a.get_val(a.max().unwrap()).unwrap();
let v = a.get_val(a.last().unwrap()).unwrap();
assert!(set.get().contains_key(v));
} else {
assert!(a.max().is_none());
assert!(a.last().is_none());
}
}
998 => {
Expand Down
33 changes: 31 additions & 2 deletions testcrate/tests/imports.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,39 @@
//! makes sure all variations of the macro compile and do not require imports
//! other than the macro itself
//! other than the macro itself, and also that fully qualified names are being
//! used

use std::num::{NonZeroU128, NonZeroU8};
#![allow(dead_code)]

use core::num::{NonZeroU128, NonZeroU8};

use triple_arena::ptr_struct;

mod std {}
mod alloc {}
struct Result {}
struct Option {}
trait Hash {}
trait Clone {}
trait Copy {}
trait PartialEq {}
trait Eq {}
trait PartialOrd {}
trait Ord {}
trait Ptr {}
trait PtrInx {}
trait PtrGen {}
trait Default {}
trait Debug {}
trait Display {}

trait Recast {}
trait Serialize {}
trait Deserialize {}

// so the default uses are correct
trait NonZeroUsize {}
trait NonZeroU64 {}

ptr_struct!(P0[NonZeroU128](NonZeroU128));
ptr_struct!(P1[NonZeroU128]());
ptr_struct!(P2[NonZeroU128]);
Expand Down
41 changes: 40 additions & 1 deletion testcrate/tests/interarena.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use rand_xoshiro::{rand_core::SeedableRng, Xoshiro128StarStar};
use rand_xoshiro::{
rand_core::{RngCore, SeedableRng},
Xoshiro128StarStar,
};
use testcrate::{
fuzz_fill_inst, std_arena, std_chain, std_chain_no_gen, std_ord, std_surject, CKey, CVal, A, P1,
};
Expand Down Expand Up @@ -158,3 +161,39 @@ fn clone_from_to_recast() {
assert_eq!(a1.get(p).unwrap(), (key, val));
});
}

// also retests a bunch of misc stuff
#[test]
fn ord_arena_order() {
let mut rng = Xoshiro128StarStar::seed_from_u64(0);
let mut set_of_vecs = vec![];
for _ in 0..A {
let mut v = vec![];
for _ in 0..(rng.next_u32() % 16) {
v.push((rng.next_u32() % 16, rng.next_u64() % 16));
}
v.sort();
v.dedup_by(|(k0, _), (k1, _)| k0 == k1);
set_of_vecs.push(v);
}
let mut set_of_arenas: Vec<OrdArena<P1, u32, u64>> = vec![];
for v in &set_of_vecs {
set_of_arenas.push(OrdArena::from_iter(v.iter().copied()))
}
set_of_vecs.sort();
// first use `PartialOrd`
let mut tmp = set_of_arenas.clone();
tmp.sort_by(|a, b| a.partial_cmp(b).unwrap());
let res: Vec<Vec<(u32, u64)>> = tmp
.iter()
.map(|a| a.iter().map(|(_, k, v)| (*k, *v)).collect())
.collect();
assert_eq!(set_of_vecs, res);
// use `Ord`
set_of_arenas.sort();
let res: Vec<Vec<(u32, u64)>> = set_of_arenas
.iter()
.map(|a| a.iter().map(|(_, k, v)| (*k, *v)).collect())
.collect();
assert_eq!(set_of_vecs, res);
}
Loading
Loading