Skip to content

Commit

Permalink
feat: Dynamic index for slice insert and remove (#3624)
Browse files Browse the repository at this point in the history
# Description

## Problem\*

Resolves #2462 

## Summary\*

This PR simply builds upon #3617
by including some tests that use a dynamic index on SliceInsert and
SliceRemove.

## Additional Context

## Documentation\*

Check one:
- [ ] No documentation needed.
- [ ] Documentation included in this PR.
- [ ] **[Exceptional Case]** Documentation to be submitted in a separate
PR.

# PR Checklist\*

- [X] I have tested the changes locally.
- [X] I have formatted the changes with [Prettier](https://prettier.io/)
and/or `cargo fmt` on default settings.
  • Loading branch information
vezenovm authored Nov 30, 2023
1 parent f41e354 commit 3ab0504
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 19 deletions.
16 changes: 2 additions & 14 deletions noir_stdlib/src/slice.nr
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,16 @@ impl<T> [T] {
#[builtin(slice_pop_front)]
pub fn pop_front(_self: Self) -> (T, Self) { }

pub fn insert(self, _index: Field, _elem: T) -> Self {
// TODO(#2462): Slice insert with a dynamic index
crate::assert_constant(_index);
self.__slice_insert(_index, _elem)
}

/// Insert an element at a specified index, shifting all elements
/// after it to the right
#[builtin(slice_insert)]
fn __slice_insert(_self: Self, _index: Field, _elem: T) -> Self { }

pub fn remove(self, _index: Field) -> (Self, T) {
// TODO(#2462): Slice remove with a dynamic index
crate::assert_constant(_index);
self.__slice_remove(_index)
}
pub fn insert(_self: Self, _index: Field, _elem: T) -> Self { }

/// Remove an element at a specified index, shifting all elements
/// after it to the left, returning the altered slice and
/// the removed element
#[builtin(slice_remove)]
fn __slice_remove(_self: Self, _index: Field) -> (Self, T) { }
pub fn remove(_self: Self, _index: Field) -> (Self, T) { }

// Append each element of the `other` slice to the end of `self`.
// This returns a new slice and leaves both input slices unchanged.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,13 @@ fn dynamic_slice_merge_if(mut slice: [Field], x: Field) {
let (first_elem, rest_of_slice) = popped_slice.pop_front();
assert(first_elem == 12);
assert(rest_of_slice.len() == 6);
// TODO(#2462): SliceInsert and SliceRemove with a dynamic index are not yet implemented in ACIR gen
slice = rest_of_slice.insert(2, 20);

slice = rest_of_slice.insert(x - 2, 20);
assert(slice[2] == 20);
assert(slice[6] == 30);
assert(slice.len() == 7);
// TODO(#2462): SliceInsert and SliceRemove with a dynamic index are not yet implemented in ACIR gen
let (removed_slice, removed_elem) = slice.remove(3);

let (removed_slice, removed_elem) = slice.remove(x - 1);
// The deconstructed tuple assigns to the slice but is not seen outside of the if statement
// without a direct assignment
slice = removed_slice;
Expand Down
93 changes: 92 additions & 1 deletion test_programs/execution_success/slice_struct_field/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,98 @@ fn test_complex_intrinsic_nested_slices(mut foo_parents: [FooParent], y: Field)
assert(foo_parents[1].foos[0].b[3] == 20);
assert(foo_parents[1].foos[0].bar.inner == [100, 101, 102]);

test_insert_remove_const_index(foo_parents, y, foo);

// Check values before insertion
assert(foo_parents[1].foos[1].a == 4);
assert(foo_parents[1].foos[1].b[0] == 5);
assert(foo_parents[1].foos[1].b[1] == 6);
assert(foo_parents[1].foos[1].b[2] == 5000);
assert(foo_parents[1].foos[1].b[3] == 21);
assert(foo_parents[1].foos[1].bar.inner == [103, 104, 105]);

assert(foo_parents[1].foos.len() == 5);
assert(foo_parents[1].foos[2].a == 50);
assert(foo_parents[1].foos[2].b[0] == 5);
assert(foo_parents[1].foos[2].b[2] == 5000);
assert(foo_parents[1].foos[2].bar.inner == [106, 107, 108]);

assert(foo_parents[1].foos[3].a == 10);
assert(foo_parents[1].foos[3].b[0] == 11);
assert(foo_parents[1].foos[3].b[2] == 23);
assert(foo_parents[1].foos[3].bar.inner == [109, 110, 111]);

foo_parents[y - 2].foos = foo_parents[y - 2].foos.insert(y - 1, foo);
assert(foo_parents[1].foos.len() == 6);

// Check values correctly moved after insertion
assert(foo_parents[1].foos[0].a == 1);
assert(foo_parents[1].foos[0].b[0] == 2);
assert(foo_parents[1].foos[0].b[1] == 3);
assert(foo_parents[1].foos[0].b[2] == 20);
assert(foo_parents[1].foos[0].b[3] == 20);
assert(foo_parents[1].foos[0].bar.inner == [100, 101, 102]);

assert(foo_parents[1].foos[1].a == 4);
assert(foo_parents[1].foos[1].b[0] == 5);
assert(foo_parents[1].foos[1].b[1] == 6);
assert(foo_parents[1].foos[1].b[2] == 5000);
assert(foo_parents[1].foos[1].b[3] == 21);
assert(foo_parents[1].foos[1].bar.inner == [103, 104, 105]);

assert(foo_parents[1].foos[2].a == 40);
assert(foo_parents[1].foos[2].b[0] == 14);
assert(foo_parents[1].foos[2].b[2] == 16);
assert(foo_parents[1].foos[2].bar.inner == [109, 110, 111]);

assert(foo_parents[1].foos[3].a == 50);
assert(foo_parents[1].foos[3].b[0] == 5);
assert(foo_parents[1].foos[3].b[2] == 5000);
assert(foo_parents[1].foos[3].bar.inner == [106, 107, 108]);

assert(foo_parents[1].foos[4].a == 10);
assert(foo_parents[1].foos[4].b[0] == 11);
assert(foo_parents[1].foos[4].b[2] == 23);
assert(foo_parents[1].foos[4].bar.inner == [109, 110, 111]);

assert(foo_parents[1].foos[5].a == 10);
assert(foo_parents[1].foos[5].b[0] == 11);
assert(foo_parents[1].foos[5].b[2] == 23);
assert(foo_parents[1].foos[5].bar.inner == [109, 110, 111]);

let (rest_of_slice, removed_elem) = foo_parents[y - 2].foos.remove(y - 1);
foo_parents[1].foos = rest_of_slice;

// Check that the accurate element was removed
assert(removed_elem.a == 40);
assert(removed_elem.b[0] == 14);
assert(removed_elem.b[2] == 16);
assert(removed_elem.bar.inner == [109, 110, 111]);

// Check that we have altered our slice accurately following a removal
assert(foo_parents[1].foos[1].a == 4);
assert(foo_parents[1].foos[1].b[0] == 5);
assert(foo_parents[1].foos[1].b[1] == 6);
assert(foo_parents[1].foos[1].b[2] == 5000);
assert(foo_parents[1].foos[1].b[3] == 21);
assert(foo_parents[1].foos[1].bar.inner == [103, 104, 105]);

assert(foo_parents[1].foos[2].a == 50);
assert(foo_parents[1].foos[2].b[0] == 5);
assert(foo_parents[1].foos[2].b[2] == 5000);
assert(foo_parents[1].foos[2].bar.inner == [106, 107, 108]);

assert(foo_parents[1].foos[3].a == 10);
assert(foo_parents[1].foos[3].b[0] == 11);
assert(foo_parents[1].foos[3].b[2] == 23);
assert(foo_parents[1].foos[3].bar.inner == [109, 110, 111]);

assert(foo_parents[1].foos[4].b[0] == 11);
assert(foo_parents[1].foos[4].b[2] == 23);
assert(foo_parents[1].foos[4].bar.inner == [109, 110, 111]);
}

fn test_insert_remove_const_index(mut foo_parents: [FooParent], y: Field, foo: Foo) {
// Check values before insertion
assert(foo_parents[1].foos[1].a == 4);
assert(foo_parents[1].foos[1].b[0] == 5);
Expand Down Expand Up @@ -377,5 +469,4 @@ fn test_complex_intrinsic_nested_slices(mut foo_parents: [FooParent], y: Field)
assert(foo_parents[1].foos[4].b[0] == 11);
assert(foo_parents[1].foos[4].b[2] == 23);
assert(foo_parents[1].foos[4].bar.inner == [109, 110, 111]);

}

0 comments on commit 3ab0504

Please sign in to comment.