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

feat: add array range and reverse functions #7159

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
71 changes: 67 additions & 4 deletions noir_stdlib/src/array/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,24 @@ use crate::runtime::is_unconstrained;
mod check_shuffle;
mod quicksort;

/// Creates a new array containing numbers from 0 to N-1.
/// This is a utility function to create arrays from ranges.
///
/// Example:
/// ```noir
/// fn main() {
/// let arr = std::array::range(5);
/// assert(arr == [0, 1, 2, 3, 4]);
/// }
/// ```
pub fn range<T>(size: Field) -> [Field] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The T generic parameter is not used, and technically this returns a slice, rather than an array.
size is usually expressed as u32.
Returning Field seems a bit specific; the library so far is completely generic.

Perhaps something like std::array::from_fn would be a more flexible alternative to make an actual array of a given size, with content created for each index given to a lambda as u32 between 0 and N. You could use it to cast to Field, or map it to a range other than 0..N, e.g. by an offset.

let mut result = [];
for i in 0..size {
result.push(i);
}
result
}

impl<T, let N: u32> [T; N] {
/// Returns the length of this array.
///
Expand Down Expand Up @@ -136,6 +154,28 @@ impl<T, let N: u32> [T; N] {
}
ret
}

/// Returns a new array with elements in reverse order.
/// The original array remains untouched.
///
/// Example:
/// ```noir
/// fn main() {
/// let arr = [1, 2, 3];
/// let reversed = arr.reverse();
/// assert(reversed == [3, 2, 1]);
/// }
/// ```
pub fn reverse(self) -> Self {
let mut result = self;
let len = self.len();
for i in 0..(len / 2) {
let temp = result[i];
result[i] = result[len - 1 - i];
result[len - 1 - i] = temp;
}
result
}
}

impl<T, let N: u32> [T; N]
Expand All @@ -157,7 +197,7 @@ where
/// }
/// ```
pub fn sort(self) -> Self {
self.sort_via(|a, b| a <= b)
self.sort_via(|a: T, b: T| a <= b)
}
}

Expand All @@ -184,10 +224,11 @@ where
/// }
/// ```
pub fn sort_via<Env>(self, ordering: fn[Env](T, T) -> bool) -> Self {
/// Safety: `sorted` array is checked to be:
/// a. a permutation of `input`'s elements
/// b. satisfying the predicate `ordering`
unsafe {
/*@safety: `sorted` array is checked to be:
a. a permutation of `input`'s elements
b. satisfying the predicate `ordering`
*/
let sorted = quicksort::quicksort(self, ordering);

if !is_unconstrained() {
Expand Down Expand Up @@ -232,4 +273,26 @@ mod test {
fn map_empty() {
assert_eq([].map(|x| x + 1), []);
}

#[test]
fn test_range() {
let arr = range(5);
assert_eq(arr, [0, 1, 2, 3, 4]);

let empty = range(0);
assert_eq(empty, []);
}

#[test]
fn test_reverse() {
let arr = [1, 2, 3, 4, 5];
let reversed = arr.reverse();
assert_eq(reversed, [5, 4, 3, 2, 1]);

let empty: [Field; 0] = [];
assert_eq(empty.reverse(), []);

let single = [1];
assert_eq(single.reverse(), [1]);
}
}
Loading