Skip to content

Commit

Permalink
add picoset to be used in search
Browse files Browse the repository at this point in the history
  • Loading branch information
emanueldima committed Feb 15, 2024
1 parent 3559c2c commit 4c8f752
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 2 deletions.
2 changes: 2 additions & 0 deletions issues.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
- explicit and implicit write support (policy, include readonly)
- fix tests, todo!() and TODO: in code

- celltrait: remove the simple get, rename get_all to get
- add extra::Cell::get that returns iterator
- implement new search algorithm (fix double kleene error, see test)
- support type selector: `hial './src/tests/rust.rs^rust/:function_item'`
- support rust/ts write: `hial './src/tests/rust.rs^rust/:function_item[-1]#label = "modified_fn_name"'`
Expand Down
5 changes: 3 additions & 2 deletions src/interpretations/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,12 @@ impl CellReaderTrait for CellReader {
}
if self.cached_value.get().is_none() {
// TODO: reading file value should return bytes, not string
let content = std::fs::read_to_string(&fe.path).map_err(|e| {
let content = std::fs::read(&fe.path).map_err(|e| {
caused(HErrKind::IO, format!("cannot read file: {:?}", fe.path), e)
})?;
let content = String::from_utf8_lossy(&content);
self.cached_value
.set(content)
.set(content.into_owned())
.map_err(|_| faulterr("cannot set cached value, it is already set"))?;
}
Ok(Value::Str(self.cached_value.get().unwrap()))
Expand Down
1 change: 1 addition & 0 deletions src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ pub mod guards;
pub mod indentation;
pub mod log;
pub mod ownrc;
pub mod picoset;
220 changes: 220 additions & 0 deletions src/utils/picoset.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
use std::collections::HashSet;
use std::hash::Hash;

const N: usize = 4;

#[derive(Debug, Clone)]
pub enum PicoSet<T: Default + Eq + Hash> {
Inline { buffer: [T; N], len: u32 },
Heap(HashSet<T>),
}

impl<T: Default + Eq + Hash + Copy, X: AsRef<[T]>> From<X> for PicoSet<T> {
fn from(set: X) -> PicoSet<T> {
let mut p = PicoSet::new();
for x in set.as_ref() {
p.insert(*x);
}
p
}
}

impl<T: Default + Eq + Hash + Copy> PicoSet<T> {
pub fn new() -> PicoSet<T> {
PicoSet::Inline {
buffer: Default::default(),
len: 0,
}
}

pub fn insert(&mut self, x: T) {
if self.contains(&x) {
return;
}
match self {
PicoSet::Inline { buffer, len } => {
if *len < N as u32 {
buffer[*len as usize] = x;
*len += 1;
} else {
let mut set = HashSet::new();
for i in 0..*len {
set.insert(buffer[i as usize]);
}
set.insert(x);
*self = PicoSet::Heap(set);
}
}
PicoSet::Heap(set) => {
set.insert(x);
}
}
}

pub fn remove(&mut self, x: &T) {
match self {
PicoSet::Inline { buffer, len } => {
for i in 0..(*len as usize) {
if buffer[i] == *x {
for j in i..(*len as usize) - 1 {
buffer[j] = buffer[j + 1];
}
*len -= 1;
return;
}
}
}
PicoSet::Heap(set) => {
set.remove(x);
}
}
}

pub fn contains(&self, x: &T) -> bool {
match self {
PicoSet::Inline { buffer, len } => buffer.iter().take(*len as usize).any(|y| y == x),
PicoSet::Heap(set) => set.contains(x),
}
}

pub fn len(&self) -> usize {
match self {
PicoSet::Inline { len, .. } => *len as usize,
PicoSet::Heap(set) => set.len(),
}
}

pub fn is_empty(&self) -> bool {
self.len() == 0
}

pub fn from_array(arg: impl AsRef<[T]>) -> PicoSet<T> {
let mut p = PicoSet::new();
for x in arg.as_ref() {
p.insert(*x);
}
p
}

pub fn iter(&self) -> PicoSetIter<'_, T> {
match self {
PicoSet::Inline { buffer, len } => PicoSetIter::Inline {
set: self,
index: 0,
},
PicoSet::Heap(set) => PicoSetIter::Heap(set.iter()),
}
}
}

impl<T: Default + Eq + Hash + Copy> Default for PicoSet<T> {
fn default() -> Self {
Self::new()
}
}

#[derive(Debug, Clone)]
pub enum PicoSetIter<'a, T: Default + Eq + Hash + Copy> {
Inline { set: &'a PicoSet<T>, index: usize },
Heap(std::collections::hash_set::Iter<'a, T>),
}

impl<'a, T: Default + Eq + Hash + Copy> Iterator for PicoSetIter<'a, T> {
type Item = T;

fn next(&mut self) -> Option<Self::Item> {
match self {
PicoSetIter::Inline { set, index } => match set {
PicoSet::Inline { buffer, len } => {
if *index < *len as usize {
let x = buffer[*index];
*index += 1;
Some(x)
} else {
None
}
}
// should never happen, the original set cannot be changed since we have a reference to it
_ => panic!("PicoSetIter::Inline: set is not Inline as expected."),
},
PicoSetIter::Heap(iter) => iter.next().copied(),
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_picoset() {
let mut p = PicoSet::new();
assert!(matches!(p, PicoSet::Inline { buffer: _, len: 0 }));
p.insert(1);
assert!(p.len() == 1);
assert!(p.contains(&1));
assert!(p.iter().collect::<Vec<_>>() == vec![1]);
p.insert(2);
assert!(p.len() == 2);
assert!(p.contains(&1));
assert!(p.contains(&2));
assert!(p.iter().collect::<Vec<_>>() == vec![1, 2]);
p.insert(2);
assert!(p.len() == 2);
assert!(p.contains(&1));
assert!(p.contains(&2));
assert!(p.iter().collect::<Vec<_>>() == vec![1, 2]);
p.insert(3);
assert!(p.len() == 3);
assert!(p.contains(&1));
assert!(p.contains(&2));
assert!(p.contains(&3));
assert!(p.iter().collect::<Vec<_>>() == vec![1, 2, 3]);
println!("{:?}", p);
p.remove(&1);
println!("{:?}", p);
assert!(p.len() == 2);
assert!(!p.contains(&1));
assert!(p.contains(&2));
assert!(p.contains(&3));
assert!(p.iter().collect::<Vec<_>>() == vec![2, 3]);
p.remove(&2);
assert!(p.len() == 1);
assert!(!p.contains(&1));
assert!(!p.contains(&2));
assert!(p.contains(&3));
assert!(p.iter().collect::<Vec<_>>() == vec![3]);
p.remove(&3);
assert!(p.is_empty());
assert!(!p.contains(&1));
assert!(!p.contains(&2));
assert!(!p.contains(&3));
assert!(p.iter().collect::<Vec<_>>() == Vec::<usize>::new());
}

#[test]
fn insert_transitions_to_heap() {
let mut set = PicoSet::<i32>::new();
for i in 0..(N + 1) {
set.insert(i as i32);
}

assert!(
matches!(set, PicoSet::Heap(_)),
"Set did not transition to Heap storage."
);
assert_eq!(
set.len(),
N + 1,
"Incorrect length after inserting elements."
);

for i in 0..(N + 1) {
assert!(
set.contains(&(i as i32)),
"Set does not contain inserted element: {}",
i
);
}
}
}

0 comments on commit 4c8f752

Please sign in to comment.