blob: dbaf881f30a2b9fec0b09ca5bc7d77e8dc242069 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#![allow(dead_code)]
use list::{LinkedList, Node};
use std::cell::RefCell;
use std::collections::HashMap;
use std::ptr::NonNull;
use std::sync::Arc;
mod list;
pub type NodeRef<T> = Arc<RefCell<T>>;
#[derive(Debug)]
struct LruEntry<T> {
node_ref: NonNull<Node<u64>>,
value: NodeRef<T>,
}
impl<T> LruEntry<T> {
fn new(node_ref: NonNull<Node<u64>>, value: NodeRef<T>) -> LruEntry<T> {
LruEntry { node_ref, value }
}
}
pub struct Iter<'a, T: 'a> {
iter: list::Iter<'a, u64>,
map: &'a HashMap<u64, LruEntry<T>>,
}
#[derive(Debug)]
pub struct LruCache<T> {
list: LinkedList<u64>,
map: HashMap<u64, LruEntry<T>>,
max_size: usize,
}
impl<T> LruCache<T> {
#[inline]
pub fn new(capacity: usize) -> LruCache<T> {
LruCache {
list: LinkedList::new(),
map: HashMap::with_capacity(capacity),
max_size: capacity,
}
}
/// Return the maximum number of key-value pairs the cache can hold.
#[inline]
pub fn capacity(&self) -> usize {
self.max_size
}
/// Returns `true` if the cache is empty.
#[inline]
pub fn is_empty(&self) -> bool {
self.list.is_empty()
}
/// Returns the length of the cache.
#[inline]
pub fn len(&self) -> usize {
self.list.len()
}
/// Adds an element first in the cache.
pub fn push(&mut self, key: u64, value: NodeRef<T>) -> bool {
let is_none = self.map.get(&key).is_none();
if is_none {
self.list.push_front(key);
let node_ref = unsafe { self.list.head_node_ref().unwrap() };
self.map.insert(key, LruEntry::new(node_ref, value));
}
is_none
}
/// Returns the value corresponding to the key.
#[inline]
pub fn find(&self, key: u64) -> Option<NodeRef<T>> {
self.map.get(&key).map(|entry| entry.value.clone())
}
/// Removes the first element and returns it, or `None` if the cache is emptry.
pub fn pop_front(&mut self) -> Option<NodeRef<T>> {
let key = self.list.pop_front()?;
self.map.remove(&key).map(|entry| entry.value)
}
/// Removes the last element and returns it, or `None` if the cache is emptry.
pub fn pop_back(&mut self) -> Option<NodeRef<T>> {
let key = self.list.pop_back()?;
self.map.remove(&key).map(|entry| entry.value)
}
/// Provides a reference to the front element, or `None` if the cache is empty.
pub fn front(&self) -> Option<&NodeRef<T>> {
let key = self.list.front()?;
self.map.get(key).map(|entry| &entry.value)
}
/// Provides a reference to the back element, or `None` if the cache is empty.
pub fn back(&self) -> Option<&NodeRef<T>> {
let key = self.list.back()?;
self.map.get(key).map(|entry| &entry.value)
}
/// Move the element corresponding to the key to the head.
pub fn move_to_head(&mut self, key: u64) {
if let Some(entry) = self.map.get_mut(&key) {
unsafe {
self.list.move_to_head(entry.node_ref);
}
}
}
/// Move the element corresponding to the key to the tail.
pub fn move_to_tail(&mut self, key: u64) {
if let Some(entry) = self.map.get_mut(&key) {
unsafe {
self.list.move_to_tail(entry.node_ref);
}
}
}
/// Change the number of key-value pairs the cache can hold.
pub fn change_capacity(&mut self, capacity: usize) {
if capacity < self.len() {
for _ in capacity..self.len() {
let _ = self.pop_back();
}
}
self.max_size = capacity;
}
/// Removes all elements from the cache.
#[inline]
pub fn clear(&mut self) {
self.list.clear();
self.map.clear();
}
/// Provides a forward iterator.
#[inline]
pub fn iter(&self) -> Iter<'_, T> {
Iter {
iter: self.list.iter(),
map: &self.map,
}
}
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a NodeRef<T>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let key = self.iter.next()?;
self.map.get(key).map(|entry| &entry.value)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<T> DoubleEndedIterator for Iter<'_, T> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
let (len, _) = self.iter.size_hint();
if len == 0 {
None
} else {
let key = self.iter.next_back()?;
self.map.get(key).map(|entry| &entry.value)
}
}
}
pub struct IntoIter<T> {
cache: LruCache<T>,
}
impl<T> Iterator for IntoIter<T> {
type Item = NodeRef<T>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.cache.pop_front()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.cache.len(), Some(self.cache.len()))
}
}
impl<T> DoubleEndedIterator for IntoIter<T> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.cache.pop_back()
}
}
impl<T> IntoIterator for LruCache<T> {
type Item = NodeRef<T>;
type IntoIter = IntoIter<T>;
/// Consumes the list into an iterator yielding elements by value.
#[inline]
fn into_iter(self) -> IntoIter<T> {
IntoIter { cache: self }
}
}