Skip to content

Commit

Permalink
Merge branch 'feature/dict-from-array' into tycho
Browse files Browse the repository at this point in the history
  • Loading branch information
Rexagon committed Jul 3, 2024
2 parents 491a0b9 + 51cf8f2 commit 5265634
Show file tree
Hide file tree
Showing 6 changed files with 793 additions and 6 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ harness = false
name = "usage_cell"
harness = false

[[bench]]
name = "dict_from_slice"
harness = false

[workspace]
members = ["proc"]

Expand Down
64 changes: 64 additions & 0 deletions benches/dict_from_slice.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
use everscale_types::cell::*;
use everscale_types::dict::*;
use rand::distributions::{Distribution, Standard};
use rand::{Rng, SeedableRng};

fn build_dict_impl<K, V>(id: impl Into<String>, sizes: &[usize], c: &mut Criterion)
where
Standard: Distribution<K> + Distribution<V>,
K: Store + DictKey + Ord,
V: Store,
{
let mut rng = rand_xorshift::XorShiftRng::from_seed([0u8; 16]);

let mut group = c.benchmark_group(id);

for size in sizes {
let mut values = (0..*size)
.map(|_| (rng.gen::<K>(), rng.gen::<V>()))
.collect::<Vec<_>>();

group.bench_with_input(BenchmarkId::new("inserts", size), &values, |b, values| {
b.iter(|| {
let mut result = Dict::<K, V>::new();
for (key, value) in values {
result.add(key, value).unwrap();
}
black_box(result);
});
});

values.sort_by(|(l, _), (r, _)| l.cmp(r));
group.bench_with_input(BenchmarkId::new("leaves", size), &values, |b, values| {
b.iter(|| {
let result = Dict::<K, V>::try_from_sorted_slice(values).unwrap();
black_box(result);
});
});
}
}

fn build_dict_group(c: &mut Criterion) {
macro_rules! decl_dict_benches {
($(($k:ty, $v:ident): [$($n:literal),+]),*$(,)?) => {
$({
let id = format!(
"build_dict({},{})",
stringify!($k), stringify!($v)
);
build_dict_impl::<$k, $v>(id, &[$($n),+], c);
});*
};
}

decl_dict_benches![
(u8, u64): [10, 256],
(u16, u64): [10, 100, 256, 1000, 10000],
(u32, u64): [10, 100, 1000, 10000, 100000],
(u64, u64): [10, 100, 1000, 5000, 10000, 20000, 25000, 50000, 75000, 100000],
];
}

criterion_group!(build_dict, build_dict_group);
criterion_main!(build_dict);
126 changes: 125 additions & 1 deletion src/dict/aug.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::borrow::Borrow;
use std::collections::BTreeMap;
use std::marker::PhantomData;

use super::{aug_dict_insert, aug_dict_remove_owned, SetMode};
use super::{aug_dict_insert, aug_dict_remove_owned, build_aug_dict_from_sorted_iter, SetMode};
use crate::cell::*;
use crate::error::*;
use crate::util::*;
Expand Down Expand Up @@ -284,6 +285,60 @@ where
for<'a> A: AugDictExtra + Store + Load<'a>,
V: Store,
{
/// Builds a dictionary from a sorted collection.
pub fn try_from_btree<Q, E, T>(sorted: &BTreeMap<Q, (E, T)>) -> Result<Self, Error>
where
Q: Borrow<K>,
E: Borrow<A>,
T: Borrow<V>,
K: Ord,
{
let root = ok!(build_aug_dict_from_sorted_iter(
sorted
.iter()
.map(|(k, (a, v))| (k.borrow(), a.borrow(), v.borrow())),
K::BITS,
A::comp_add,
&mut Cell::empty_context()
));

let mut result = Self {
dict: Dict::from_raw(root),
extra: A::default(),
_key: PhantomData,
_value: PhantomData,
};
ok!(result.update_root_extra());
Ok(result)
}

/// Builds a dictionary from a sorted slice.
pub fn try_from_sorted_slice<Q, E, T>(sorted: &[(Q, E, T)]) -> Result<Self, Error>
where
Q: Borrow<K>,
E: Borrow<A>,
T: Borrow<V>,
K: Ord,
{
let root = ok!(build_aug_dict_from_sorted_iter(
sorted
.iter()
.map(|(k, a, v)| (k.borrow(), a.borrow(), v.borrow())),
K::BITS,
A::comp_add,
&mut Cell::empty_context()
));

let mut result = Self {
dict: Dict::from_raw(root),
extra: A::default(),
_key: PhantomData,
_value: PhantomData,
};
ok!(result.update_root_extra());
Ok(result)
}

/// Sets the augmented value associated with the key in the aug dictionary.
///
/// Use [`set_ext`] if you need to use a custom cell context.
Expand Down Expand Up @@ -787,6 +842,13 @@ mod tests {
}
}

impl rand::distributions::Distribution<SomeValue> for rand::distributions::Standard {
#[inline]
fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> SomeValue {
SomeValue(rand::distributions::Standard.sample(rng))
}
}

#[test]
fn dict_set() {
let mut dict = AugDict::<u32, OrCmp, u16>::new();
Expand Down Expand Up @@ -937,4 +999,66 @@ mod tests {
assert!(new_dict.is_empty());
assert_eq!(new_dict.root_extra(), &CurrencyCollection::ZERO);
}

#[test]
fn build_from_array() {
let entries = [
(0u32, SomeValue(123), 1u32),
(1, SomeValue(10), 2),
(2, SomeValue(20), 4),
(2, SomeValue(20), 3),
(3, SomeValue(40), 4),
(4, SomeValue(50), 5),
];
// let entries = [
// (534837844, SomeValue(331123), 3117028142),
// (1421713188, SomeValue(5345345), 3155891450),
// (1526242096, SomeValue(567567), 2789399854),
// (1971086295, SomeValue(5345), 1228713494),
// (4258889371, SomeValue(4956495), 3256452222),
// ];
let result = AugDict::<u32, SomeValue, u32>::try_from_sorted_slice(&entries).unwrap();

let mut dict = AugDict::<u32, SomeValue, u32>::new();
for (k, a, v) in entries {
dict.add(k, a, v).unwrap();
}

println!("{}", result.dict.root.as_ref().unwrap().display_tree());
println!(
"BOC: {}",
crate::boc::BocRepr::encode_base64(&result).unwrap()
);

assert_eq!(result, dict);
}

#[test]
fn build_from_any_array() {
for _ in 0..100 {
let n = 1 + rand::random::<usize>() % 1000;
let mut entries = (0..n)
.map(|_| {
(
rand::random::<u32>(),
rand::random::<SomeValue>(),
rand::random::<u32>(),
)
})
.collect::<Vec<_>>();
entries.sort_by_key(|(k, _, _)| *k);

let built_from_dict =
AugDict::<u32, SomeValue, u32>::try_from_sorted_slice(&entries).unwrap();

let mut dict = AugDict::<u32, SomeValue, u32>::new();
for (k, a, v) in entries {
dict.add(k, a, v).unwrap();
}

// println!("{}", built_from_dict.as_ref().unwrap().display_tree());

assert_eq!(built_from_dict, dict);
}
}
}
Loading

0 comments on commit 5265634

Please sign in to comment.