-
Notifications
You must be signed in to change notification settings - Fork 626
feat(byte_array): add slice
#8417
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
base: gilad/09-11-feat_byte_array_add_bytespan_into_
Are you sure you want to change the base?
feat(byte_array): add slice
#8417
Conversation
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
efdd998
to
d530eee
Compare
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.
Reviewable status: 0 of 3 files reviewed, 5 unresolved discussions (waiting on @TomerStarkware)
corelib/src/byte_array.cairo
line 628 at r2 (raw file):
/// Returns a slice of the ByteSpan from the given start position with the given length. fn slice(self: @ByteSpan, start: usize, len: usize) -> Option<ByteSpan> {
should slice alway be option based?
Code quote:
/// Returns a slice of the ByteSpan from the given start position with the given length.
fn slice(self: @ByteSpan, start: usize, len: usize) -> Option<ByteSpan> {
corelib/src/byte_array.cairo
line 636 at r2 (raw file):
} let abs_start = upcast(*self.first_char_start_offset) + start;
this may be a fallible function now - and i d
Code quote:
let abs_start = upcast(*self.first_char_start_offset) + start;
corelib/src/byte_array.cairo
line 653 at r2 (raw file):
ByteSpan { data: [].span(), first_char_start_offset: downcast(0).unwrap(),
Suggestion:
first_char_start_offset: 0,
corelib/src/byte_array.cairo
line 664 at r2 (raw file):
true => slice_bytes31((*self.data[end_word]).into(), BYTES_IN_BYTES31, 0, end_offset), false => slice_bytes31(*self.remainder_word, remainder_len, 0, end_offset), };
Suggestion:
// Multi-word slice - data words plus optional remainder
let remainder = if end_word < data_len {
slice_bytes31((*self.data[end_word]).into(), BYTES_IN_BYTES31, 0, end_offset)
} else {
slice_bytes31(*self.remainder_word, remainder_len, 0, end_offset)
};
corelib/src/bytes_31.cairo
line 191 at r2 (raw file):
let (without_prefix_and_suffix, _) = split_bytes31(without_suffix, start + len, len); without_prefix_and_suffix }
no reason for this to be in another file.
Code quote:
/// Extracts a slice of bytes from a word.
/// Returns bytes [start, start+len) where byte 0 is the leftmost (most significant) byte.
/// The input `bytes31` and the output `bytes31`s are represented using `felt252`s to improve
/// performance.
///
/// Note: this function assumes that:
/// 1. `word` is validly convertible to a `bytes31` which has no more than `word_len` bytes of data.
/// 2. `start + len <= word_len`.
/// 3. `word_len <= BYTES_IN_BYTES31`.
/// If these assumptions are not met, it can corrupt the result. Thus, this should be a
/// private function. We could add masking/assertions but it would be more expensive.
pub(crate) fn slice_bytes31(word: felt252, word_len: usize, start: usize, len: usize) -> felt252 {
if len == 0 {
return 0;
}
// Remove suffix: keep only bytes [0, start+len).
let (_, without_suffix) = split_bytes31(word, word_len, word_len - (start + len));
let (without_prefix_and_suffix, _) = split_bytes31(without_suffix, start + len, len);
without_prefix_and_suffix
}
d530eee
to
68080c4
Compare
d1f1e71
to
3ba3ba2
Compare
68080c4
to
d4f7ade
Compare
3ba3ba2
to
7b0a77a
Compare
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.
Reviewable status: 0 of 3 files reviewed, 5 unresolved discussions (waiting on @orizi and @TomerStarkware)
corelib/src/byte_array.cairo
line 628 at r2 (raw file):
Previously, orizi wrote…
should slice alway be option based?
Wasn't sure, my reasoning was to allow users more choice: they can use slice
for checked behavior, and indexing for panic behavior.
Also this allow us to add later on slice_unchecked
like rust
used to do (they renamed slice->get but point still stands), whereas making this return non-option will require a breaking change later on.
Cons: in array Span::slice
we dont return an option, and it sucks to break consistency with it.
WDYT?
corelib/src/byte_array.cairo
line 636 at r2 (raw file):
Previously, orizi wrote…
this may be a fallible function now - and i d
Missing the end of yr message?
You mean addition overflow or upcast?
upcast
says it panics in Sierra stage if the cast isn't legal, but since its boundedint<0,31> it should always fir in start: usize
, unless there's something i'm missing about this.
However there were 3 overflow issues (unchecked arithmetic), fixed and added tests for all cases. The remaining unchecked arithmetic ops are guaranteed to succeed (they don't involve user input so are legal by construction).
corelib/src/bytes_31.cairo
line 191 at r2 (raw file):
Previously, orizi wrote…
no reason for this to be in another file.
Done.
corelib/src/byte_array.cairo
line 653 at r2 (raw file):
ByteSpan { data: [].span(), first_char_start_offset: downcast(0).unwrap(),
Done.
corelib/src/byte_array.cairo
line 664 at r2 (raw file):
true => slice_bytes31((*self.data[end_word]).into(), BYTES_IN_BYTES31, 0, end_offset), false => slice_bytes31(*self.remainder_word, remainder_len, 0, end_offset), };
Done + other place.
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.
Reviewable status: 0 of 3 files reviewed, 1 unresolved discussion (waiting on @TomerStarkware)
corelib/src/byte_array.cairo
line 628 at r2 (raw file):
Previously, giladchase wrote…
Wasn't sure, my reasoning was to allow users more choice: they can use
slice
for checked behavior, and indexing for panic behavior.
Also this allow us to add later onslice_unchecked
likerust
used to do (they renamed slice->get but point still stands), whereas making this return non-option will require a breaking change later on.Cons: in array
Span::slice
we dont return an option, and it sucks to break consistency with it.WDYT?
sounds to leave as is.
corelib/src/byte_array.cairo
line 636 at r2 (raw file):
Previously, giladchase wrote…
Missing the end of yr message?
You mean addition overflow or upcast?
upcast
says it panics in Sierra stage if the cast isn't legal, but since its boundedint<0,31> it should always fir instart: usize
, unless there's something i'm missing about this.However there were 3 overflow issues (unchecked arithmetic), fixed and added tests for all cases. The remaining unchecked arithmetic ops are guaranteed to succeed (they don't involve user input so are legal by construction).
it was mostly about the add - that can't really fail - but better now in any case.
corelib/src/byte_array.cairo
line 635 at r3 (raw file):
if start.checked_add(len)? > self.len() { return None; }
consider - the later accesses would fail as well - so you maybe not need to do all the calculations.
Code quote:
if start.checked_add(len)? > self.len() {
return None;
}
d4f7ade
to
e9c1e71
Compare
7b0a77a
to
558ac51
Compare
e9c1e71
to
d2487b7
Compare
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.
Reviewable status: 0 of 3 files reviewed, 1 unresolved discussion (waiting on @orizi and @TomerStarkware)
corelib/src/byte_array.cairo
line 636 at r2 (raw file):
Previously, orizi wrote…
it was mostly about the add - that can't really fail - but better now in any case.
OK, note that reverted the checked_add here in favor of the one above, due to this thread
corelib/src/byte_array.cairo
line 635 at r3 (raw file):
Previously, orizi wrote…
consider - the later accesses would fail as well - so you maybe not need to do all the calculations.
Right, only the first one was needed, removed the later two checked_add
s.
558ac51
to
9c5f473
Compare
235db8b
to
eeaa0bf
Compare
45abe52
to
afd7694
Compare
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.
Reviewable status: 0 of 3 files reviewed, 2 unresolved discussions (waiting on @TomerStarkware)
corelib/src/test/byte_array_test.cairo
line 713 at r6 (raw file):
// Test to demonstrate the optimization of lazy start-offset trimming. // Multiple slicing operations on remainder word should be more efficient. let ba: ByteArray = "abcdef"; // 10 bytes in remainder
i see 6.
Code quote:
let ba: ByteArray = "abcdef"; // 10 bytes in remainder
corelib/src/byte_array.cairo
line 691 at r6 (raw file):
/// Returns a slice of the ByteSpan from the given start position with the given length. fn slice(self: @ByteSpan, start: usize, len: usize) -> Option<ByteSpan> {
and use range style trait.
Suggestion:
fn slice(self: ByteSpan,
afd7694
to
9ab073e
Compare
6be5ef1
to
c5a931d
Compare
b38e4cc
to
20ea89a
Compare
c5a931d
to
7e5ddc0
Compare
20ea89a
to
bc5dfbf
Compare
7e5ddc0
to
da91b41
Compare
bc5dfbf
to
50fdc8e
Compare
da91b41
to
12b43bb
Compare
50fdc8e
to
079403d
Compare
12b43bb
to
595a075
Compare
079403d
to
04b050b
Compare
595a075
to
dc1e38d
Compare
7331124
to
cfb20a9
Compare
02b3ccb
to
b769bea
Compare
cfb20a9
to
471439b
Compare
b769bea
to
ac251eb
Compare
471439b
to
5b966b7
Compare
ac251eb
to
672763a
Compare
5b966b7
to
f03f22e
Compare
672763a
to
127e45d
Compare
f03f22e
to
4ffc000
Compare
1. When a slice ends before a word boundary (it's last word isn't a full 31 bytes long) , it's last word is copied into the remainder word. Rationale: this is consistent with `ByteArray`'s `pending word`, and allows slices of full bytes31 that include an end_suffix to be shifted-right without allocating a new array. 2. When slices include a start-offset, the offset is applied lazily only upon `into`ing into a `ByteArray`, otherwise it's only recorded in the `first_char_start_offset` field.
127e45d
to
1000d8d
Compare
4ffc000
to
5faa3d7
Compare
When a slice ends before a word boundary (it's last word isn't a full 31 bytes long)
, it's last word is copied into the remainder word.
Rationale: this is consistent with
ByteArray
'spending word
, and allows slices of full bytes31that include an end_suffix to be shifted-right without allocating a new array.
When slices include a start-offset, the offset is applied lazily only upon
into
ing into aByteArray
, otherwise it's only recorded in thefirst_char_start_offset
field.