Skip to content

Commit

Permalink
perf: implement mem_eq and use it for set_add (lambdaclass#1198)
Browse files Browse the repository at this point in the history
  • Loading branch information
Oppen authored and kariy committed Jun 23, 2023
1 parent ffa0fda commit e562f14
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 5 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

#### Upcoming Changes

* feat: implement `mem_eq` function to test for equality of two ranges in memory [#1198](https://github.com/lambdaclass/cairo-rs/pull/1198)
* perf: use `mem_eq` in `set_add` [#1198](https://github.com/lambdaclass/cairo-rs/pull/1198)

* feat: wrap big variants of `HintError`, `VirtualMachineError`, `RunnerError`, `MemoryError`, `MathError`, `InsufficientAllocatedCellsError` in `Box` [#1193](https://github.com/lambdaclass/cairo-rs/pull/1193)
* BREAKING: all tuple variants of `HintError` with a single `Felt252` or multiple elements now receive a single `Box`

Expand Down
6 changes: 1 addition & 5 deletions src/hint_processor/builtin_hint_processor/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use crate::{
types::errors::math_errors::MathError,
vm::{errors::hint_errors::HintError, vm_core::VirtualMachine},
};
use core::cmp::Ordering;
use felt::Felt252;
use num_traits::{One, ToPrimitive, Zero};

Expand Down Expand Up @@ -41,10 +40,7 @@ pub fn set_add(
let range_limit = (set_end_ptr - set_ptr)?;

for i in 0..range_limit {
if matches!(
vm.memcmp(elm_ptr, (set_ptr + elm_size * i)?, elm_size),
(Ordering::Equal, _)
) {
if vm.mem_eq(elm_ptr, (set_ptr + elm_size * i)?, elm_size) {
insert_value_from_var_name("index", Felt252::new(i), vm, ids_data, ap_tracking)?;
return insert_value_from_var_name(
"is_elm_in_set",
Expand Down
4 changes: 4 additions & 0 deletions src/vm/vm_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,10 @@ impl VirtualMachine {
self.segments.memory.memcmp(lhs, rhs, len)
}

pub fn mem_eq(&self, lhs: Relocatable, rhs: Relocatable, len: usize) -> bool {
self.segments.memory.mem_eq(lhs, rhs, len)
}

///Gets `n_ret` return values from memory
pub fn get_return_values(&self, n_ret: usize) -> Result<Vec<MaybeRelocatable>, MemoryError> {
let addr = (self.run_context.get_ap() - n_ret)
Expand Down
48 changes: 48 additions & 0 deletions src/vm/vm_memory/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,54 @@ impl Memory {
(Ordering::Equal, len)
}

/// Compares two ranges of values in memory of length `len`
/// Returns the ordering and the first relative position at which they differ
/// Special cases:
/// - `lhs` exists in memory but `rhs` doesn't -> (Ordering::Greater, 0)
/// - `rhs` exists in memory but `lhs` doesn't -> (Ordering::Less, 0)
/// - None of `lhs` or `rhs` exist in memory -> (Ordering::Equal, 0)
/// Everything else behaves much like `memcmp` in C.
/// This is meant as an optimization for hints to avoid allocations.
pub(crate) fn mem_eq(&self, lhs: Relocatable, rhs: Relocatable, len: usize) -> bool {
if lhs == rhs {
return true;
}
let get_segment = |idx: isize| {
if idx.is_negative() {
self.temp_data.get(-(idx + 1) as usize)
} else {
self.data.get(idx as usize)
}
};
match (
get_segment(lhs.segment_index),
get_segment(rhs.segment_index),
) {
(None, None) => {
return true;
}
(Some(_), None) => {
return false;
}
(None, Some(_)) => {
return false;
}
(Some(lhs_segment), Some(rhs_segment)) => {
let (lhs_start, rhs_start) = (lhs.offset, rhs.offset);
for i in 0..len {
let (lhs, rhs) = (
lhs_segment.get(lhs_start + i),
rhs_segment.get(rhs_start + i),
);
if lhs != rhs {
return false;
}
}
}
};
true
}

/// Gets a range of memory values from addr to addr + size
/// The outputed range may contain gaps if the original memory has them
pub fn get_range(&self, addr: Relocatable, size: usize) -> Vec<Option<Cow<MaybeRelocatable>>> {
Expand Down

0 comments on commit e562f14

Please sign in to comment.