Unverified Commit 3d337f46 authored by Michael Müller's avatar Michael Müller Committed by GitHub
Browse files

Evaluate migration of `SmallVec` to `min_const_generics` (#598)

* Get rid of `generic-array`

* Remove comment

* Fmt and get rid of feature flags

* Include Vec

* Make clippy happy

* Add `into_inner` back in

* Do not allocate heap memory

* Use `array_init` for initializing

* Revert me: Activate `const-generics` feature in `array-init`

* Remove `feature(array_map)`

* Remove feature flag, since it is now stable on nightly

* Add feature `ink-unstable`

* Put `LazyArray` behind `ink-unstable` feature

* Remove newline

* Allow dead code in `LazyArray` when `ink-unstable` missing

* Remove unnecessary allow
parent e22a0feb
Pipeline #123198 failed with stages
in 5 minutes and 56 seconds
......@@ -25,8 +25,7 @@ scale = { package = "parity-scale-codec", version = "2.0", default-features = fa
derive_more = { version = "0.99", default-features = false, features = ["from", "display"] }
scale-info = { version = "0.5", default-features = false, features = ["derive"], optional = true }
cfg-if = "1.0"
array-init = "1.0"
generic-array = "0.14.1"
array-init = { version = "1.0", default-features = false, features = ["const-generics"] }
# Workaround: we actually just need criterion as a dev-dependency, but
# there is an issue with a doubly included std lib when executing
......@@ -54,6 +53,7 @@ std = [
"scale-info/std",
]
ink-fuzz-tests = ["std"]
ink-unstable = ["std"]
[[bench]]
name = "bench_lazy"
......
......@@ -22,6 +22,7 @@ pub mod binary_heap;
pub mod bitstash;
pub mod bitvec;
pub mod hashmap;
#[cfg(feature = "ink-unstable")]
pub mod smallvec;
pub mod stash;
pub mod vec;
......@@ -32,11 +33,14 @@ pub use self::{
bitstash::BitStash,
bitvec::Bitvec,
hashmap::HashMap,
smallvec::SmallVec,
stash::Stash,
vec::Vec,
};
#[cfg(feature = "ink-unstable")]
#[doc(inline)]
pub use self::smallvec::SmallVec;
/// Extends the lifetime 'a to the outliving lifetime 'b for the given reference.
///
/// # Note
......
......@@ -16,29 +16,24 @@ use super::{
Iter,
SmallVec,
};
use crate::{
lazy::LazyArrayLength,
traits::PackedLayout,
};
use crate::traits::PackedLayout;
use core::iter::{
Extend,
FromIterator,
};
impl<T, N> Drop for SmallVec<T, N>
impl<T, const N: usize> Drop for SmallVec<T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
fn drop(&mut self) {
self.clear_cells()
}
}
impl<T, N> core::ops::Index<u32> for SmallVec<T, N>
impl<T, const N: usize> core::ops::Index<u32> for SmallVec<T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
type Output = T;
......@@ -56,10 +51,9 @@ where
}
}
impl<T, N> core::ops::IndexMut<u32> for SmallVec<T, N>
impl<T, const N: usize> core::ops::IndexMut<u32> for SmallVec<T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
fn index_mut(&mut self, index: u32) -> &mut Self::Output {
let len = self.len();
......@@ -75,10 +69,9 @@ where
}
}
impl<'a, T: 'a, N> IntoIterator for &'a SmallVec<T, N>
impl<'a, T: 'a, const N: usize> IntoIterator for &'a SmallVec<T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
type Item = &'a T;
type IntoIter = Iter<'a, T, N>;
......@@ -88,10 +81,9 @@ where
}
}
impl<T, N> Extend<T> for SmallVec<T, N>
impl<T, const N: usize> Extend<T> for SmallVec<T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
fn extend<I>(&mut self, iter: I)
where
......@@ -103,10 +95,9 @@ where
}
}
impl<T, N> FromIterator<T> for SmallVec<T, N>
impl<T, const N: usize> FromIterator<T> for SmallVec<T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
fn from_iter<I>(iter: I) -> Self
where
......@@ -118,10 +109,9 @@ where
}
}
impl<T, N> core::cmp::PartialEq for SmallVec<T, N>
impl<T, const N: usize> core::cmp::PartialEq for SmallVec<T, N>
where
T: PartialEq + PackedLayout,
N: LazyArrayLength<T>,
{
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() {
......@@ -131,9 +121,4 @@ where
}
}
impl<T, N> core::cmp::Eq for SmallVec<T, N>
where
T: Eq + PackedLayout,
N: LazyArrayLength<T>,
{
}
impl<T, const N: usize> core::cmp::Eq for SmallVec<T, N> where T: Eq + PackedLayout {}
......@@ -15,16 +15,14 @@
use super::SmallVec;
use crate::{
collections::extend_lifetime,
lazy::LazyArrayLength,
traits::PackedLayout,
};
/// An iterator over shared references to the elements of a small storage vector.
#[derive(Debug, Clone, Copy)]
pub struct Iter<'a, T, N>
pub struct Iter<'a, T, const N: usize>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
/// The storage vector to iterate over.
vec: &'a SmallVec<T, N>,
......@@ -34,10 +32,9 @@ where
end: u32,
}
impl<'a, T, N> Iter<'a, T, N>
impl<'a, T, const N: usize> Iter<'a, T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
/// Creates a new iterator for the given storage vector.
pub(crate) fn new(vec: &'a SmallVec<T, N>) -> Self {
......@@ -54,10 +51,9 @@ where
}
}
impl<'a, T, N> Iterator for Iter<'a, T, N>
impl<'a, T, const N: usize> Iterator for Iter<'a, T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
type Item = &'a T;
......@@ -86,17 +82,11 @@ where
}
}
impl<'a, T, N> ExactSizeIterator for Iter<'a, T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
}
impl<'a, T, const N: usize> ExactSizeIterator for Iter<'a, T, N> where T: PackedLayout {}
impl<'a, T, N> DoubleEndedIterator for Iter<'a, T, N>
impl<'a, T, const N: usize> DoubleEndedIterator for Iter<'a, T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
fn next_back(&mut self) -> Option<Self::Item> {
<Self as DoubleEndedIterator>::nth_back(self, 0)
......@@ -118,10 +108,9 @@ where
/// An iterator over exclusive references to the elements of a small storage vector.
#[derive(Debug)]
pub struct IterMut<'a, T, N>
pub struct IterMut<'a, T, const N: usize>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
/// The storage vector to iterate over.
vec: &'a mut SmallVec<T, N>,
......@@ -131,10 +120,9 @@ where
end: u32,
}
impl<'a, T, N> IterMut<'a, T, N>
impl<'a, T, const N: usize> IterMut<'a, T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
/// Creates a new iterator for the given storage vector.
pub(crate) fn new(vec: &'a mut SmallVec<T, N>) -> Self {
......@@ -152,10 +140,9 @@ where
}
}
impl<'a, T, N> IterMut<'a, T, N>
impl<'a, T, const N: usize> IterMut<'a, T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
fn get_mut<'b>(&'b mut self, at: u32) -> Option<&'a mut T> {
self.vec.get_mut(at).map(|value| {
......@@ -171,10 +158,9 @@ where
}
}
impl<'a, T, N> Iterator for IterMut<'a, T, N>
impl<'a, T, const N: usize> Iterator for IterMut<'a, T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
type Item = &'a mut T;
......@@ -203,17 +189,11 @@ where
}
}
impl<'a, T, N> ExactSizeIterator for IterMut<'a, T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
}
impl<'a, T, const N: usize> ExactSizeIterator for IterMut<'a, T, N> where T: PackedLayout {}
impl<'a, T, N> DoubleEndedIterator for IterMut<'a, T, N>
impl<'a, T, const N: usize> DoubleEndedIterator for IterMut<'a, T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
fn next_back(&mut self) -> Option<Self::Item> {
<Self as DoubleEndedIterator>::nth_back(self, 0)
......
......@@ -34,7 +34,6 @@ use crate::{
lazy::{
Lazy,
LazyArray,
LazyArrayLength,
},
traits::PackedLayout,
};
......@@ -55,10 +54,9 @@ type Index = u32;
/// `Vec` due to the internal differences.
/// - Allows to store up to N elements.
#[derive(Debug)]
pub struct SmallVec<T, N>
pub struct SmallVec<T, const N: usize>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
/// The current length of the small vector.
len: Lazy<u32>,
......@@ -66,20 +64,18 @@ where
elems: LazyArray<T, N>,
}
impl<T, N> Default for SmallVec<T, N>
impl<T, const N: usize> Default for SmallVec<T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
fn default() -> Self {
Self::new()
}
}
impl<T, N> SmallVec<T, N>
impl<T, const N: usize> SmallVec<T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
/// Clears the underlying storage cells of the storage vector.
///
......@@ -103,10 +99,9 @@ where
}
}
impl<T, N> SmallVec<T, N>
impl<T, const N: usize> SmallVec<T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
/// Creates a new empty vector.
pub fn new() -> Self {
......@@ -135,10 +130,9 @@ where
}
}
impl<T, N> SmallVec<T, N>
impl<T, const N: usize> SmallVec<T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
/// Returns an iterator yielding shared references to all elements.
///
......@@ -196,10 +190,9 @@ where
}
}
impl<T, N> SmallVec<T, N>
impl<T, const N: usize> SmallVec<T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
/// Appends an element to the back of the vector.
pub fn push(&mut self, value: T) {
......@@ -213,10 +206,9 @@ where
}
}
impl<T, N> SmallVec<T, N>
impl<T, const N: usize> SmallVec<T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
/// Pops the last element from the vector and returns it.
//
......
......@@ -13,22 +13,17 @@
// limitations under the License.
use super::SmallVec;
use crate::{
lazy::LazyArrayLength,
traits::{
KeyPtr,
PackedLayout,
SpreadLayout,
},
use crate::traits::{
KeyPtr,
PackedLayout,
SpreadLayout,
};
use generic_array::typenum::Unsigned;
#[cfg(feature = "std")]
const _: () = {
use crate::{
lazy::LazyArray,
traits::StorageLayout,
};
#[cfg(feature = "ink-unstable")]
use crate::lazy::LazyArray;
use crate::traits::StorageLayout;
use ink_metadata::layout::{
FieldLayout,
Layout,
......@@ -36,10 +31,9 @@ const _: () = {
};
use scale_info::TypeInfo;
impl<T, N> StorageLayout for SmallVec<T, N>
impl<T, const N: usize> StorageLayout for SmallVec<T, N>
where
T: PackedLayout + TypeInfo + 'static,
N: LazyArrayLength<T>,
{
fn layout(key_ptr: &mut KeyPtr) -> Layout {
Layout::Struct(StructLayout::new(vec![
......@@ -53,12 +47,11 @@ const _: () = {
}
};
impl<T, N> SpreadLayout for SmallVec<T, N>
impl<T, const N: usize> SpreadLayout for SmallVec<T, N>
where
T: PackedLayout,
N: LazyArrayLength<T>,
{
const FOOTPRINT: u64 = 1 + <N as Unsigned>::U64;
const FOOTPRINT: u64 = 1 + N as u64;
fn pull_spread(ptr: &mut KeyPtr) -> Self {
Self {
......
......@@ -20,17 +20,16 @@ use crate::{
},
Lazy,
};
use generic_array::typenum::*;
use ink_primitives::Key;
#[test]
fn new_vec_works() {
let vec = <SmallVec<i32, U4>>::new();
let vec = <SmallVec<i32, 4>>::new();
assert!(vec.is_empty());
assert_eq!(vec.len(), 0);
assert_eq!(vec.get(0), None);
assert!(vec.iter().next().is_none());
let default = <SmallVec<i32, U4> as Default>::default();
let default = <SmallVec<i32, 4> as Default>::default();
assert!(default.is_empty());
assert_eq!(default.len(), 0);
assert_eq!(vec.get(0), None);
......@@ -40,7 +39,7 @@ fn new_vec_works() {
#[test]
fn from_iterator_works() {
let some_primes = [b'A', b'B', b'C', b'D'];
assert_eq!(some_primes.iter().copied().collect::<SmallVec<_, U4>>(), {
assert_eq!(some_primes.iter().copied().collect::<SmallVec<_, 4>>(), {
let mut vec = SmallVec::new();
for prime in &some_primes {
vec.push(*prime)
......@@ -53,20 +52,20 @@ fn from_iterator_works() {
#[should_panic]
fn from_iterator_too_many() {
let some_primes = [b'A', b'B', b'C', b'D', b'E'];
let _ = some_primes.iter().copied().collect::<SmallVec<_, U4>>();
let _ = some_primes.iter().copied().collect::<SmallVec<_, 4>>();
}
#[test]
fn from_empty_iterator_works() {
assert_eq!(
[].iter().copied().collect::<SmallVec<u8, U4>>(),
[].iter().copied().collect::<SmallVec<u8, 4>>(),
SmallVec::new(),
);
}
#[test]
fn first_last_of_empty() {
let mut vec = <SmallVec<u8, U4>>::new();
let mut vec = <SmallVec<u8, 4>>::new();
assert_eq!(vec.first(), None);
assert_eq!(vec.first_mut(), None);
assert_eq!(vec.last(), None);
......@@ -75,14 +74,14 @@ fn first_last_of_empty() {
#[test]
fn pop_on_empty_works() {
let mut vec = <SmallVec<u8, U4>>::new();
let mut vec = <SmallVec<u8, 4>>::new();
assert_eq!(vec.pop(), None);
}
#[test]
fn push_pop_first_last_works() {
/// Asserts conditions are met for the given storage vector.
fn assert_vec<F, L>(vec: &SmallVec<u8, U4>, len: u32, first: F, last: L)
fn assert_vec<F, L>(vec: &SmallVec<u8, 4>, len: u32, first: F, last: L)
where
F: Into<Option<u8>>,
L: Into<Option<u8>>,
......@@ -127,18 +126,18 @@ fn push_beyond_limits_fails() {
let mut vec = [b'A', b'B', b'C', b'D']
.iter()
.copied()
.collect::<SmallVec<_, U4>>();
.collect::<SmallVec<_, 4>>();
vec.push(b'E');
}
/// Creates a storage vector from the given slice.
fn vec_from_slice(slice: &[u8]) -> SmallVec<u8, U4> {
slice.iter().copied().collect::<SmallVec<u8, U4>>()
fn vec_from_slice(slice: &[u8]) -> SmallVec<u8, 4> {
slice.iter().copied().collect::<SmallVec<u8, 4>>()
}
/// Asserts that the the given ordered storage vector elements are equal to the
/// ordered elements of the given slice.
fn assert_eq_slice(vec: &SmallVec<u8, U4>, slice: &[u8]) {
fn assert_eq_slice(vec: &SmallVec<u8, 4>, slice: &[u8]) {
assert_eq!(vec.len() as usize, slice.len());
let vec_copy = vec.iter().copied().collect::<Vec<u8>>();
assert_eq!(vec_copy.as_slice(), slice);
......@@ -371,7 +370,7 @@ fn spread_layout_push_pull_works() -> ink_env::Result<()> {
// Load the pushed storage vector into another instance and check that
// both instances are equal:
let vec2 =
<SmallVec<u8, U4> as SpreadLayout>::pull_spread(&mut KeyPtr::from(root_key));
<SmallVec<u8, 4> as SpreadLayout>::pull_spread(&mut KeyPtr::from(root_key));
assert_eq!(vec1, vec2);
Ok(())
})
......@@ -392,7 +391,7 @@ fn spread_layout_clear_works() {
// vector's length property cannot read a value:
SpreadLayout::clear_spread(&vec1, &mut KeyPtr::from(root_key));
let _ =
<SmallVec<u8, U4> as SpreadLayout>::pull_spread(&mut KeyPtr::from(root_key));
<SmallVec<u8, 4> as SpreadLayout>::pull_spread(&mut KeyPtr::from(root_key));
Ok(())
})
.unwrap()
......@@ -405,7 +404,7 @@ fn storage_is_cleared_completely_after_pull_lazy() {
let root_key = Key::from([0x42; 32]);
let lazy_vec = Lazy::new(vec_from_slice(&[b'a', b'b', b'c', b'd']));
SpreadLayout::push_spread(&lazy_vec, &mut KeyPtr::from(root_key));
let pulled_vec = <Lazy<SmallVec<u8, U4>> as SpreadLayout>::pull_spread(
let pulled_vec = <Lazy<SmallVec<u8, 4>> as SpreadLayout>::pull_spread(
&mut KeyPtr::from(root_key),
);
......@@ -438,7 +437,7 @@ fn drop_works() {
let setup_result = std::panic::catch_unwind(|| {
let vec = vec_from_slice(&[b'a', b'b', b'c', b'd']);
SpreadLayout::push_spread(&vec, &mut KeyPtr::from(root_key));
let _ = <SmallVec<u8, U4> as SpreadLayout>::pull_spread(&mut KeyPtr::from(
let _ = <SmallVec<u8, 4> as SpreadLayout>::pull_spread(&mut KeyPtr::from(
root_key,
));
// vec is dropped which should clear the cells
......@@ -456,7 +455,7 @@ fn drop_works() {
assert_eq!(used_cells, 0);
let _ =
<SmallVec<u8, U4> as SpreadLayout>::pull_spread(&mut KeyPtr::from(root_key));
<SmallVec<u8, 4> as SpreadLayout>::pull_spread(&mut KeyPtr::from(root_key));
Ok(())
})
.unwrap()
......
......@@ -38,6 +38,7 @@ impl<T> CacheCell<T> {
}
/// Returns the inner value.
#[allow(dead_code)]
pub fn into_inner(self) -> T {
self.inner.into_inner()
}
......
......@@ -31,37 +31,11 @@ use core::{
mem,
ptr::NonNull,
};
use generic_array::{
typenum::{
UInt,
UTerm,
Unsigned,
B0,
B1,
},
ArrayLength,
GenericArray,
};
use ink_primitives::Key;
/// The index type used in the lazy storage chunk.
pub type Index = u32;
/// Utility trait for helping with lazy array construction.
pub trait LazyArrayLength<T>:
ArrayLength<CacheCell<Option<StorageEntry<T>>>> + Unsigned
{
}
impl<T> LazyArrayLength<T> for UTerm {}
impl<T, N: ArrayLength<CacheCell<Option<StorageEntry<T>>>>> LazyArrayLength<T>
for UInt<N, B0>
{
}
impl<T, N: ArrayLength<CacheCell<Option<StorageEntry<T>>>>> LazyArrayLength<T>
for UInt<N, B1>
{
}
/// A lazy storage array that spans over N storage cells.