-
Notifications
You must be signed in to change notification settings - Fork 39
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
Implement Range for OpStack #338
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,8 +2,7 @@ use std::fmt::Display; | |
use std::fmt::Formatter; | ||
use std::fmt::Result as FmtResult; | ||
use std::num::TryFromIntError; | ||
use std::ops::Index; | ||
use std::ops::IndexMut; | ||
use std::ops::{Index, IndexMut, Range, RangeInclusive}; | ||
|
||
use arbitrary::Arbitrary; | ||
use get_size::GetSize; | ||
|
@@ -183,13 +182,69 @@ impl Index<usize> for OpStack { | |
} | ||
} | ||
|
||
fn compute_range(start: usize, end: usize, len: usize) -> (usize, usize) { | ||
match (start, end) { | ||
(0, end) if end == len => (0, len), | ||
(0, end) => (len - end, len), | ||
_ => (len - end, len - start), | ||
} | ||
} | ||
Comment on lines
+185
to
+191
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The name does not really describe what the function does. A better name could be Furthermore, I don't think the special cases are necessary since they all collapse into the general case. fn flip_range(start: usize, end: usize, len: usize) -> (usize, usize) {
(len - end, len - start)
} |
||
|
||
impl Index<Range<usize>> for OpStack { | ||
type Output = [BFieldElement]; | ||
|
||
fn index(&self, range: Range<usize>) -> &Self::Output { | ||
let (start, end) = compute_range(range.start, range.end, self.stack.len()); | ||
let mut stack = self.stack[start..end].to_vec(); | ||
stack.reverse(); | ||
Box::leak(Box::new(stack)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a creative way of solving this. 😃 However, I feel uncomfortable with consciously introducing memory leaks. The approach you take here indicates to me that implementing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Introduction of
In this case we do not reverse Additionally, we can update
I wonder if this make sense. |
||
} | ||
} | ||
|
||
fn compute_range_inclusive(start: usize, end: usize, len: usize) -> (usize, usize) { | ||
match (start, end) { | ||
(0, end) if end == len - 1 => (0, len), | ||
(0, end) => (len - end - 1, len), | ||
_ => (len - end - 1, len - start), | ||
} | ||
} | ||
|
||
impl Index<RangeInclusive<usize>> for OpStack { | ||
type Output = [BFieldElement]; | ||
|
||
fn index(&self, range: RangeInclusive<usize>) -> &Self::Output { | ||
let (start, end) = compute_range_inclusive(*range.start(), *range.end(), self.stack.len()); | ||
let mut stack = self.stack[start..end].to_vec(); | ||
stack.reverse(); | ||
Box::leak(Box::new(stack)) | ||
} | ||
} | ||
|
||
impl IndexMut<usize> for OpStack { | ||
fn index_mut(&mut self, index: usize) -> &mut Self::Output { | ||
let top_of_stack = self.len() - 1; | ||
&mut self.stack[top_of_stack - index] | ||
} | ||
} | ||
|
||
impl IndexMut<Range<usize>> for OpStack { | ||
fn index_mut(&mut self, range: Range<usize>) -> &mut Self::Output { | ||
let (start, end) = compute_range(range.start, range.end, self.stack.len()); | ||
let slice = &mut self.stack[start..end]; | ||
slice.reverse(); | ||
slice | ||
} | ||
} | ||
|
||
impl IndexMut<RangeInclusive<usize>> for OpStack { | ||
fn index_mut(&mut self, range: RangeInclusive<usize>) -> &mut Self::Output { | ||
let (start, end) = compute_range_inclusive(*range.start(), *range.end(), self.stack.len()); | ||
let slice = &mut self.stack[start..end]; | ||
slice.reverse(); | ||
slice | ||
} | ||
} | ||
|
||
impl Index<OpStackElement> for OpStack { | ||
type Output = BFieldElement; | ||
|
||
|
@@ -198,12 +253,69 @@ impl Index<OpStackElement> for OpStack { | |
} | ||
} | ||
|
||
impl Index<Range<OpStackElement>> for OpStack { | ||
type Output = [BFieldElement]; | ||
|
||
fn index(&self, range: Range<OpStackElement>) -> &Self::Output { | ||
let (start, end) = compute_range( | ||
usize::from(range.start), | ||
usize::from(range.end), | ||
self.stack.len(), | ||
); | ||
let mut stack = self.stack[start..end].to_vec(); | ||
stack.reverse(); | ||
Box::leak(Box::new(stack)) | ||
} | ||
} | ||
|
||
impl Index<RangeInclusive<OpStackElement>> for OpStack { | ||
type Output = [BFieldElement]; | ||
|
||
fn index(&self, range: RangeInclusive<OpStackElement>) -> &Self::Output { | ||
let (start, end) = compute_range_inclusive( | ||
usize::from(range.start()), | ||
usize::from(range.end()), | ||
self.stack.len(), | ||
); | ||
let mut stack = self.stack[start..end].to_vec(); | ||
stack.reverse(); | ||
|
||
Box::leak(Box::new(stack)) | ||
} | ||
} | ||
|
||
impl IndexMut<OpStackElement> for OpStack { | ||
fn index_mut(&mut self, stack_element: OpStackElement) -> &mut Self::Output { | ||
&mut self[usize::from(stack_element)] | ||
} | ||
} | ||
|
||
impl IndexMut<Range<OpStackElement>> for OpStack { | ||
fn index_mut(&mut self, range: Range<OpStackElement>) -> &mut Self::Output { | ||
let (start, end) = compute_range( | ||
usize::from(range.start), | ||
usize::from(range.end), | ||
self.stack.len(), | ||
); | ||
let slice = &mut self.stack[start..end]; | ||
slice.reverse(); | ||
slice | ||
} | ||
} | ||
|
||
impl IndexMut<RangeInclusive<OpStackElement>> for OpStack { | ||
fn index_mut(&mut self, range: RangeInclusive<OpStackElement>) -> &mut Self::Output { | ||
let (start, end) = compute_range_inclusive( | ||
usize::from(range.start()), | ||
usize::from(range.end()), | ||
self.stack.len(), | ||
); | ||
let slice = &mut self.stack[start..end]; | ||
slice.reverse(); | ||
slice | ||
} | ||
} | ||
|
||
impl IntoIterator for OpStack { | ||
type Item = BFieldElement; | ||
type IntoIter = std::vec::IntoIter<Self::Item>; | ||
|
@@ -1025,4 +1137,159 @@ mod tests { | |
let expected_len = 2 * OpStackElement::COUNT - 1; | ||
prop_assert_eq!(expected_len, op_stack.len()); | ||
} | ||
|
||
fn setup_op_stack() -> OpStack { | ||
OpStack { | ||
stack: bfe_vec![1, 2, 3, 4, 5], | ||
underflow_io_sequence: vec![], | ||
} | ||
} | ||
|
||
fn reversed_range(stack: &[BFieldElement], start: usize, end: usize) -> Vec<BFieldElement> { | ||
stack[start..end].iter().rev().copied().collect() | ||
} | ||
|
||
#[test] | ||
fn test_opstack_index_range() { | ||
let op_stack = setup_op_stack(); | ||
|
||
test_opstack_range1_internal(&op_stack, 0..5, 0..5); | ||
test_opstack_range1_internal(&op_stack, 0..2, 3..5); | ||
test_opstack_range1_internal(&op_stack, 1..3, 2..4); | ||
} | ||
|
||
fn test_opstack_range1_internal( | ||
op_stack: &OpStack, | ||
actual_range: Range<usize>, | ||
expected_range: Range<usize>, | ||
) { | ||
let (start, end) = (actual_range.start, actual_range.end); | ||
let actual = op_stack[start..end].to_vec(); | ||
|
||
let (start, end) = (expected_range.start, expected_range.end); | ||
let expected = reversed_range(&op_stack.stack, start, end); | ||
assert_eq!(actual, expected); | ||
} | ||
|
||
// #[test] | ||
// fn test_opstack_index_range1() { | ||
// let op_stack = setup_op_stack(); | ||
// let len = op_stack.stack.len(); | ||
|
||
// // Test boundary ranges | ||
// let actual = op_stack[0..len].to_vec(); | ||
// let expected = reversed_range(&op_stack.stack, 0, len); | ||
// assert_eq!(actual, expected); | ||
|
||
// // Test start boundary range | ||
// let actual = op_stack[0..2].to_vec(); | ||
// let expected = reversed_range(&op_stack.stack, 3, len); | ||
// assert_eq!(actual, expected); | ||
|
||
// // Test typical range | ||
// let actual = op_stack[1..3].to_vec(); | ||
// let expected = reversed_range(&op_stack.stack, 2, 4); | ||
// assert_eq!(actual, expected); | ||
|
||
// // ADDRESS len = 5, how to handle out of bounds in vector? | ||
// // let actual = op_stack[1..6].to_vec(); | ||
// } | ||
|
||
#[test] | ||
fn test_opstack_index_range_inclusive() { | ||
let op_stack = setup_op_stack(); | ||
let len = op_stack.stack.len(); | ||
let last = len - 1; | ||
|
||
// Test boundary ranges | ||
let actual = op_stack[0..=last].to_vec(); | ||
let expected = reversed_range(&op_stack.stack, 0, len); | ||
assert_eq!(actual, expected); | ||
|
||
// Test start boundary range | ||
let actual = op_stack[0..=2].to_vec(); | ||
let expected = reversed_range(&op_stack.stack, 2, len); | ||
assert_eq!(actual, expected); | ||
|
||
// Test typical range | ||
let actual = op_stack[1..=3].to_vec(); | ||
let expected = reversed_range(&op_stack.stack, 1, 4); | ||
assert_eq!(actual, expected); | ||
} | ||
|
||
fn test_opstack_range_mut_inclusive( | ||
actual_range: RangeInclusive<usize>, | ||
expected_range: RangeInclusive<usize>, | ||
) { | ||
let mut op_stack = setup_op_stack(); | ||
|
||
let (start, end) = (*expected_range.start(), *expected_range.end()); | ||
let mut expected = op_stack.stack.clone()[start..=end].to_vec(); | ||
expected.reverse(); | ||
|
||
let (start, end) = (*actual_range.start(), *actual_range.end()); | ||
let actual = op_stack.index_mut(start..=end); | ||
|
||
assert_eq!(actual, expected); | ||
} | ||
|
||
#[test] | ||
fn test_opstack_index_mut_range_inclusive() { | ||
test_opstack_range_mut_inclusive(0..=4, 0..=4); | ||
test_opstack_range_mut_inclusive(0..=2, 2..=4); | ||
test_opstack_range_mut_inclusive(1..=2, 2..=3); | ||
} | ||
|
||
// #[test] | ||
// fn test_opstack_index_mut_range_inclusive() { | ||
// let mut op_stack = setup_op_stack(); | ||
// let len = op_stack.stack.len(); | ||
// let mut expected = op_stack.stack.clone(); | ||
// expected.reverse(); | ||
|
||
// // Test boundary ranges | ||
// let actual = op_stack.index_mut(0..=len-1); | ||
// assert_eq!(actual, expected); | ||
|
||
// // Test start boundary range | ||
// let mut op_stack = setup_op_stack(); | ||
// let mut expected = op_stack.stack.clone()[2..].to_vec(); | ||
// expected.reverse(); | ||
// let actual = op_stack.index_mut(0..=2); | ||
// assert_eq!(actual, expected); | ||
|
||
// // Test typical range | ||
// let mut op_stack = setup_op_stack(); | ||
// let mut expected = op_stack.stack.clone()[2..4].to_vec(); | ||
// expected.reverse(); | ||
// let actual = op_stack.index_mut(1..=2); | ||
// assert_eq!(actual, expected); | ||
// } | ||
|
||
// #[test] | ||
// fn test_opstack_index_mut_range_inclusive_usize() { | ||
// let mut op_stack = setup_op_stack(); | ||
// let len = op_stack.stack.len(); | ||
// let last = len - 1; | ||
// let mut expected = op_stack.stack.clone(); | ||
// expected.reverse(); | ||
|
||
// // Test boundary ranges | ||
// let actual = op_stack.index_mut(0..=last); | ||
// assert_eq!(actual, expected); | ||
|
||
// // Test start boundary range | ||
// let mut op_stack = setup_op_stack(); | ||
// let mut expected = op_stack.stack.clone()[2..].to_vec(); | ||
// expected.reverse(); | ||
// let actual = op_stack.index_mut(0..=2); | ||
// assert_eq!(actual, expected); | ||
|
||
// // Test typical range | ||
// let mut op_stack = setup_op_stack(); | ||
// let mut expected = op_stack.stack.clone()[1..4].to_vec(); | ||
// expected.reverse(); | ||
// let actual = op_stack.index_mut(1..=3); | ||
// assert_eq!(actual, expected); | ||
// } | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's the wrong way around. 🙂 You've applied item granularity “module”, whereas granularity “item” results in one line per
use
d type. See also here.