Skip to content

Commit

Permalink
Merge pull request #5 from drink7036290/refactor_q146_q460_pq_vhm
Browse files Browse the repository at this point in the history
Refactor the code to use the generic cache, including priority_queue …
  • Loading branch information
drink7036290 authored Dec 21, 2024
2 parents deaea06 + bbe338b commit cdf8f7b
Show file tree
Hide file tree
Showing 30 changed files with 601 additions and 554 deletions.
1 change: 0 additions & 1 deletion implementations/q146_lru_cache/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ edition = "2024"
license = "MIT"

[dependencies]
priority-queue = "2.1.1"
intrusive-collections = "0.9.7"
cache_util = { path = "../../utilities/cache_util", version = "0.1.0" }

Expand Down
52 changes: 13 additions & 39 deletions implementations/q146_lru_cache/src/priority_queue.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
use priority_queue::PriorityQueue;
use std::cmp::Reverse;
use std::time::SystemTime;

use cache_util::HeapNode;
use cache_util::HashMapStorage;
use cache_util::{Cache, GenericCache};
use cache_util::{EvictionPolicyPQ, LRUHeapNode};

pub struct LRUCache {
pq: PriorityQueue<i32, Reverse<HeapNode>>,
capacity: usize,
cache: GenericCache<EvictionPolicyPQ<LRUHeapNode>, HashMapStorage>,
}

/**
Expand All @@ -16,43 +13,20 @@ pub struct LRUCache {
impl LRUCache {
pub fn new(capacity: i32) -> Self {
Self {
pq: PriorityQueue::new(),
capacity: capacity as usize,
}
}

pub fn get(&mut self, key: i32) -> i32 {
match self.pq.get(&key) {
Some((_, rev_node)) => {
let val = rev_node.0.val;

self.pq.change_priority_by(&key, |p| {
p.0.last_access = SystemTime::now();
});

val
}
None => -1,
cache: GenericCache::new(
EvictionPolicyPQ::<LRUHeapNode>::default(),
HashMapStorage::default(),
capacity as usize,
),
}
}

pub fn put(&mut self, key: i32, value: i32) {
match self.pq.get(&key) {
Some((_, _)) => {
self.pq.change_priority_by(&key, |p| {
p.0.last_access = SystemTime::now();

p.0.val = value;
});
}
None => {
if self.pq.len() == self.capacity {
self.pq.pop();
}
self.cache.put(key, value);
}

self.pq.push(key, Reverse(HeapNode::new(key, value)));
}
}
pub fn get(&mut self, key: i32) -> i32 {
self.cache.get(&key).unwrap_or(-1)
}
}

Expand Down
203 changes: 13 additions & 190 deletions implementations/q146_lru_cache/src/vec_hashmap.rs
Original file line number Diff line number Diff line change
@@ -1,209 +1,32 @@
use cache_util::HeapNode;
use std::collections::HashMap;

use std::cmp::Ordering;
use std::time::SystemTime;
use cache_util::HashMapStorage;
use cache_util::{Cache, GenericCache};
use cache_util::{EvictionPolicyVHM, KeyAwareHeapNode, LRUHeapNode};

pub struct LRUCache {
arr: Vec<HeapNode>,
map: HashMap<i32, usize>, // key -> vec's index
capacity: usize,
cache: GenericCache<EvictionPolicyVHM<KeyAwareHeapNode<LRUHeapNode>>, HashMapStorage>,
}

/**
* `&self` means the method takes an immutable reference.
* If you need a mutable reference, change it to `&mut self` instead.
*/
impl LRUCache {
fn get_node(&self, index: usize) -> Option<&HeapNode> {
match index.cmp(&self.arr.len()) {
Ordering::Less => Some(&self.arr[index]),
_ => None,
}
}

fn get_node_mut(&mut self, index: usize) -> Option<&mut HeapNode> {
match index.cmp(&self.arr.len()) {
Ordering::Less => Some(&mut self.arr[index]),
_ => None,
}
}

fn get_parent(&self, index: usize) -> Option<(usize, &HeapNode)> {
match index {
0 => None,
_ => {
let parent_index = (index - 1) >> 1;
self.get_node(parent_index).map(|node| (parent_index, node))
}
}
}

fn get_left_child(&self, index: usize) -> Option<(usize, &HeapNode)> {
let left_child_index = (index << 1) + 1;
self.get_node(left_child_index)
.map(|node| (left_child_index, node))
}

fn get_right_child(&self, index: usize) -> Option<(usize, &HeapNode)> {
let right_child_index = (index << 1) + 2;
self.get_node(right_child_index)
.map(|node| (right_child_index, node))
}

fn swap_nodes_with_key(&mut self, key1: i32, index1: usize, key2: i32, index2: usize) {
match self.map.get_mut(&key1) {
Some(v) => *v = index2,
None => panic!("key {} not found in map", key1),
}

match self.map.get_mut(&key2) {
Some(v) => *v = index1,
None => panic!("key {} not found in map", key2),
}

self.arr.swap(index1, index2);
}

fn swap_nodes(&mut self, index1: usize, index2: usize) {
let key1 = match self.get_node(index1) {
Some(v) => v.key,
None => panic!("Could not find node with vec index {} ", index1),
};

let key2 = match self.get_node(index2) {
Some(v) => v.key,
None => panic!("Could not find node with vec index {} ", index2),
};

self.swap_nodes_with_key(key1, index1, key2, index2);
}

fn sift_up(&mut self, index: usize) {
let mut index = index;

while let Some((parent_index, parent_node)) = self.get_parent(index) {
let node = match self.get_node(index) {
Some(v) => v,
None => break,
};

// already in order
if *node >= *parent_node {
break;
}

// swap with parent
self.swap_nodes_with_key(node.key, index, parent_node.key, parent_index);
index = parent_index;
}
}

fn sift_down(&mut self, index: usize) {
let mut index = index;

while let Some((left_child_index, left_child_node)) = self.get_left_child(index) {
let node = match self.get_node(index) {
Some(v) => v,
None => break,
};

// right child exists
if let Some((right_child_index, right_child_node)) = self.get_right_child(index) {
// right child is smaller
if *left_child_node >= *right_child_node {
// already in order
if *node <= *right_child_node {
break;
}

// swap with right child
self.swap_nodes_with_key(
node.key,
index,
right_child_node.key,
right_child_index,
);
index = right_child_index;

continue;
}
}

// already in order
if *node <= *left_child_node {
break;
}

// swap with left child
self.swap_nodes_with_key(node.key, index, left_child_node.key, left_child_index);
index = left_child_index;
}
}

pub fn new(capacity: i32) -> Self {
Self {
arr: Vec::new(),
map: HashMap::new(),
capacity: capacity as usize,
}
}

pub fn get(&mut self, key: i32) -> i32 {
let index = match self.map.get(&key) {
Some(v) => *v,
None => return -1,
};

let node = match self.get_node_mut(index) {
Some(v) => v,
None => panic!(
"vec index {} found with key {} but node is None",
index, key
cache: GenericCache::new(
EvictionPolicyVHM::<KeyAwareHeapNode<LRUHeapNode>>::new(),
HashMapStorage::default(),
capacity as usize,
),
};

node.last_access = SystemTime::now();

let val = node.val;
self.sift_down(index);
val
}
}

pub fn put(&mut self, key: i32, value: i32) {
let index = match self.map.get(&key) {
Some(v) => *v,
None => {
if self.arr.len() == self.capacity {
let last_index = self.arr.len() - 1;

self.swap_nodes(0, last_index);
self.map.remove(&self.arr[last_index].key);
self.arr.pop();
self.sift_down(0);
}

self.arr.push(HeapNode::new(key, value));
self.map.insert(key, self.arr.len() - 1);
self.sift_up(self.arr.len() - 1);

return;
}
};

let node = match self.get_node_mut(index) {
Some(v) => v,
None => panic!(
"vec index {} found with key {} but node is None",
index, key
),
};

node.val = value;

node.last_access = SystemTime::now();
self.cache.put(key, value);
}

self.sift_down(index);
pub fn get(&mut self, key: i32) -> i32 {
self.cache.get(&key).unwrap_or(-1)
}
}

Expand Down
1 change: 0 additions & 1 deletion implementations/q460_lfu_cache/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ edition = "2024"
license = "MIT"

[dependencies]
priority-queue = "2.1.1"
intrusive-collections = "0.9.7"
cache_util = { path = "../../utilities/cache_util", version = "0.1.0" }

Expand Down
37 changes: 0 additions & 37 deletions implementations/q460_lfu_cache/src/freq_aware_heap_node.rs

This file was deleted.

3 changes: 0 additions & 3 deletions implementations/q460_lfu_cache/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
mod freq_aware_heap_node;
pub mod intrusive_two_hashmaps;
pub mod priority_queue;
pub mod two_hashmaps;
pub mod vec_hashmap;

pub use freq_aware_heap_node::*;
Loading

0 comments on commit cdf8f7b

Please sign in to comment.