Skip to content

Commit de6a232

Browse files
authored
perf: implement mem_eq and use it for set_add (#1198)
1 parent cf5768c commit de6a232

File tree

4 files changed

+56
-5
lines changed

4 files changed

+56
-5
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
#### Upcoming Changes
44

5+
* feat: implement `mem_eq` function to test for equality of two ranges in memory [#1198](https://github.com/lambdaclass/cairo-rs/pull/1198)
6+
* perf: use `mem_eq` in `set_add` [#1198](https://github.com/lambdaclass/cairo-rs/pull/1198)
7+
58
* feat: wrap big variants of `HintError`, `VirtualMachineError`, `RunnerError`, `MemoryError`, `MathError`, `InsufficientAllocatedCellsError` in `Box` [#1193](https://github.com/lambdaclass/cairo-rs/pull/1193)
69
* BREAKING: all tuple variants of `HintError` with a single `Felt252` or multiple elements now receive a single `Box`
710

src/hint_processor/builtin_hint_processor/set.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use crate::{
1111
types::errors::math_errors::MathError,
1212
vm::{errors::hint_errors::HintError, vm_core::VirtualMachine},
1313
};
14-
use core::cmp::Ordering;
1514
use felt::Felt252;
1615
use num_traits::{One, ToPrimitive, Zero};
1716

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

4342
for i in 0..range_limit {
44-
if matches!(
45-
vm.memcmp(elm_ptr, (set_ptr + elm_size * i)?, elm_size),
46-
(Ordering::Equal, _)
47-
) {
43+
if vm.mem_eq(elm_ptr, (set_ptr + elm_size * i)?, elm_size) {
4844
insert_value_from_var_name("index", Felt252::new(i), vm, ids_data, ap_tracking)?;
4945
return insert_value_from_var_name(
5046
"is_elm_in_set",

src/vm/vm_core.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,10 @@ impl VirtualMachine {
822822
self.segments.memory.memcmp(lhs, rhs, len)
823823
}
824824

825+
pub fn mem_eq(&self, lhs: Relocatable, rhs: Relocatable, len: usize) -> bool {
826+
self.segments.memory.mem_eq(lhs, rhs, len)
827+
}
828+
825829
///Gets `n_ret` return values from memory
826830
pub fn get_return_values(&self, n_ret: usize) -> Result<Vec<MaybeRelocatable>, MemoryError> {
827831
let addr = (self.run_context.get_ap() - n_ret)

src/vm/vm_memory/memory.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,54 @@ impl Memory {
398398
(Ordering::Equal, len)
399399
}
400400

401+
/// Compares two ranges of values in memory of length `len`
402+
/// Returns the ordering and the first relative position at which they differ
403+
/// Special cases:
404+
/// - `lhs` exists in memory but `rhs` doesn't -> (Ordering::Greater, 0)
405+
/// - `rhs` exists in memory but `lhs` doesn't -> (Ordering::Less, 0)
406+
/// - None of `lhs` or `rhs` exist in memory -> (Ordering::Equal, 0)
407+
/// Everything else behaves much like `memcmp` in C.
408+
/// This is meant as an optimization for hints to avoid allocations.
409+
pub(crate) fn mem_eq(&self, lhs: Relocatable, rhs: Relocatable, len: usize) -> bool {
410+
if lhs == rhs {
411+
return true;
412+
}
413+
let get_segment = |idx: isize| {
414+
if idx.is_negative() {
415+
self.temp_data.get(-(idx + 1) as usize)
416+
} else {
417+
self.data.get(idx as usize)
418+
}
419+
};
420+
match (
421+
get_segment(lhs.segment_index),
422+
get_segment(rhs.segment_index),
423+
) {
424+
(None, None) => {
425+
return true;
426+
}
427+
(Some(_), None) => {
428+
return false;
429+
}
430+
(None, Some(_)) => {
431+
return false;
432+
}
433+
(Some(lhs_segment), Some(rhs_segment)) => {
434+
let (lhs_start, rhs_start) = (lhs.offset, rhs.offset);
435+
for i in 0..len {
436+
let (lhs, rhs) = (
437+
lhs_segment.get(lhs_start + i),
438+
rhs_segment.get(rhs_start + i),
439+
);
440+
if lhs != rhs {
441+
return false;
442+
}
443+
}
444+
}
445+
};
446+
true
447+
}
448+
401449
/// Gets a range of memory values from addr to addr + size
402450
/// The outputed range may contain gaps if the original memory has them
403451
pub fn get_range(&self, addr: Relocatable, size: usize) -> Vec<Option<Cow<MaybeRelocatable>>> {

0 commit comments

Comments
 (0)