diff --git a/yarn-project/noir-private-kernel/src/crates/private-kernel-lib/src/utils.nr b/yarn-project/noir-private-kernel/src/crates/private-kernel-lib/src/utils.nr index b0d232213d68..fe3c49e09305 100644 --- a/yarn-project/noir-private-kernel/src/crates/private-kernel-lib/src/utils.nr +++ b/yarn-project/noir-private-kernel/src/crates/private-kernel-lib/src/utils.nr @@ -5,6 +5,7 @@ mod arrays; mod uint256; mod uint128; +mod bounded_vec; // if predicate == true then return lhs, else return rhs pub fn conditional_assign(predicate : bool, lhs : Field, rhs: Field) -> Field { diff --git a/yarn-project/noir-private-kernel/src/crates/private-kernel-lib/src/utils/bounded_vec.nr b/yarn-project/noir-private-kernel/src/crates/private-kernel-lib/src/utils/bounded_vec.nr new file mode 100644 index 000000000000..4851a1200c3d --- /dev/null +++ b/yarn-project/noir-private-kernel/src/crates/private-kernel-lib/src/utils/bounded_vec.nr @@ -0,0 +1,127 @@ + +struct BoundedVec { + storage: [T; MaxLen], + len: Field, +} + +impl BoundedVec { + pub fn new(initial_value: T) -> Self { + BoundedVec { storage: [initial_value; MaxLen], len: 0 } + } + + pub fn get(mut self: Self, index: Field) -> T { + assert(index as u64 < self.len as u64); + self.storage[index] + } + + pub fn get_unchecked(mut self: Self, index: Field) -> T { + self.storage[index] + } + + pub fn push(&mut self, elem: T) { + assert(self.len as u64 < MaxLen as u64); + + self.storage[self.len] = elem; + self.len += 1; + } + + pub fn push_array(&mut self, array: [T; Len]) { + let newLen = self.len + array.len(); + assert(newLen as u64 <= MaxLen as u64); + for i in 0..array.len() { + self.storage[self.len + i] = array[i]; + } + self.len = newLen; + } + + pub fn pop(&mut self) -> T { + assert(self.len as u64 > 0); + + let elem = self.storage[self.len - 1]; + self.len -= 1; + elem + } + + pub fn any(self, predicate: fn[Env](T) -> bool) -> bool { + let mut ret = false; + let mut exceeded_len = false; + for i in 0..MaxLen { + exceeded_len |= i == self.len; + if (!exceeded_len) { + ret |= predicate(self.storage[i]); + } + } + ret + } +} + +#[test] +fn test_vec_push_pop() { + let mut vec: BoundedVec = BoundedVec::new(0); + assert(vec.len == 0); + vec.push(2); + assert(vec.len == 1); + vec.push(4); + assert(vec.len == 2); + vec.push(6); + assert(vec.len == 3); + let x = vec.pop(); + assert(x == 6); + assert(vec.len == 2); + assert(vec.get(0) == 2); + assert(vec.get(1) == 4); +} + +#[test] +fn test_vec_push_array() { + let mut vec: BoundedVec = BoundedVec::new(0); + vec.push_array([2, 4]); + assert(vec.len == 2); + assert(vec.get(0) == 2); + assert(vec.get(1) == 4); +} + +#[test(should_fail)] +fn test_vec_get_out_of_bound() { + let mut vec: BoundedVec = BoundedVec::new(0); + vec.push_array([2, 4]); + let _x = vec.get(2); +} + +#[test(should_fail)] +fn test_vec_get_not_declared() { + let mut vec: BoundedVec = BoundedVec::new(0); + vec.push_array([2]); + let _x = vec.get(1); +} + +#[test(should_fail)] +fn test_vec_get_uninitialized() { + let mut vec: BoundedVec = BoundedVec::new(0); + let _x = vec.get(0); +} + +#[test(should_fail)] +fn test_vec_push_overflow() { + let mut vec: BoundedVec = BoundedVec::new(0); + vec.push(1); + vec.push(2); +} + +#[test] +fn test_vec_any() { + let mut vec: BoundedVec = BoundedVec::new(0); + vec.push_array([2, 4, 6]); + assert(vec.any(|v| v == 2) == true); + assert(vec.any(|v| v == 4) == true); + assert(vec.any(|v| v == 6) == true); + assert(vec.any(|v| v == 3) == false); +} + +#[test] +fn test_vec_any_not_default() { + let default_value = 1; + let mut vec: BoundedVec = BoundedVec::new(default_value); + vec.push_array([2, 4]); + assert(vec.any(|v| v == default_value) == false); +} \ No newline at end of file