Commit 513bfaf8 authored by Jeremy Soller's avatar Jeremy Soller

Set block size programatically

parent a0ec6670
......@@ -9,23 +9,6 @@
// except according to those terms.
//! A HashMap wrapper that holds key-value pairs in insertion order.
//!
//! # Examples
//!
//! ```
//! use linked_hash_map::LinkedHashMap;
//!
//! let mut map = LinkedHashMap::new();
//! map.insert(2, 20);
//! map.insert(1, 10);
//! map.insert(3, 30);
//! assert_eq!(map[&1], 10);
//! assert_eq!(map[&2], 20);
//! assert_eq!(map[&3], 30);
//!
//! let items: Vec<(i32, i32)> = map.iter().map(|t| (*t.0, *t.1)).collect();
//! assert_eq!(items, [(2, 20), (1, 10), (3, 30)]);
//! ```
#![forbid(missing_docs)]
#![cfg_attr(feature = "nightly", feature(hashmap_public_hasher))]
......@@ -167,18 +150,6 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
/// Inserts a key-value pair into the map. If the key already existed, the old value is
/// returned.
///
/// # Examples
///
/// ```
/// use linked_hash_map::LinkedHashMap;
/// let mut map = LinkedHashMap::new();
///
/// map.insert(1, "a");
/// map.insert(2, "b");
/// assert_eq!(map[&1], "a");
/// assert_eq!(map[&2], "b");
/// ```
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
if self.head.is_null() {
// allocate the guard node if not present
......@@ -231,39 +202,11 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
}
/// Returns the value corresponding to the key in the map.
///
/// # Examples
///
/// ```
/// use linked_hash_map::LinkedHashMap;
/// let mut map = LinkedHashMap::new();
///
/// map.insert(1, "a");
/// map.insert(2, "b");
/// map.insert(2, "c");
/// map.insert(3, "d");
///
/// assert_eq!(map.get(&1), Some(&"a"));
/// assert_eq!(map.get(&2), Some(&"c"));
/// ```
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> where K: Borrow<Q>, Q: Eq + Hash {
self.map.get(Qey::from_ref(k)).map(|e| &e.value)
}
/// Returns the mutable reference corresponding to the key in the map.
///
/// # Examples
///
/// ```
/// use linked_hash_map::LinkedHashMap;
/// let mut map = LinkedHashMap::new();
///
/// map.insert(1, "a");
/// map.insert(2, "b");
///
/// *map.get_mut(&1).unwrap() = "c";
/// assert_eq!(map.get(&1), Some(&"c"));
/// ```
pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V> where K: Borrow<Q>, Q: Eq + Hash {
self.map.get_mut(Qey::from_ref(k)).map(|e| &mut e.value)
}
......@@ -272,21 +215,6 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
///
/// If value is found, it is moved to the end of the list.
/// This operation can be used in implemenation of LRU cache.
///
/// # Examples
///
/// ```
/// use linked_hash_map::LinkedHashMap;
/// let mut map = LinkedHashMap::new();
///
/// map.insert(1, "a");
/// map.insert(2, "b");
/// map.insert(3, "d");
///
/// assert_eq!(map.get_refresh(&2), Some(&mut "b"));
///
/// assert_eq!((&2, &"b"), map.iter().rev().next().unwrap());
/// ```
pub fn get_refresh<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V> where K: Borrow<Q>, Q: Eq + Hash {
let (value, node_ptr_opt) = match self.map.get_mut(Qey::from_ref(k)) {
None => (None, None),
......@@ -303,20 +231,6 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
}
/// Removes and returns the value corresponding to the key from the map.
///
/// # Examples
///
/// ```
/// use linked_hash_map::LinkedHashMap;
/// let mut map = LinkedHashMap::new();
///
/// map.insert(2, "a");
///
/// assert_eq!(map.remove(&1), None);
/// assert_eq!(map.remove(&2), Some("a"));
/// assert_eq!(map.remove(&2), None);
/// assert_eq!(map.len(), 0);
/// ```
pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V> where K: Borrow<Q>, Q: Eq + Hash {
let removed = self.map.remove(Qey::from_ref(k));
removed.map(|mut node| {
......@@ -335,14 +249,6 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
}
/// Returns the maximum number of key-value pairs the map can hold without reallocating.
///
/// # Examples
///
/// ```
/// use linked_hash_map::LinkedHashMap;
/// let mut map: LinkedHashMap<i32, &str> = LinkedHashMap::new();
/// let capacity = map.capacity();
/// ```
pub fn capacity(&self) -> usize {
self.map.capacity()
}
......@@ -350,18 +256,6 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
/// Removes the first entry.
///
/// Can be used in implementation of LRU cache.
///
/// # Examples
///
/// ```
/// use linked_hash_map::LinkedHashMap;
/// let mut map = LinkedHashMap::new();
/// map.insert(1, 10);
/// map.insert(2, 20);
/// map.pop_front();
/// assert_eq!(map.get(&1), None);
/// assert_eq!(map.get(&2), Some(&20));
/// ```
#[inline]
pub fn pop_front(&mut self) -> Option<(K, V)> {
if self.len() > 0 {
......@@ -375,16 +269,6 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
}
/// Gets the first entry.
///
/// # Examples
///
/// ```
/// use linked_hash_map::LinkedHashMap;
/// let mut map = LinkedHashMap::new();
/// map.insert(1, 10);
/// map.insert(2, 20);
/// assert_eq!(map.front(), Some((&1, &10)));
/// ```
#[inline]
pub fn front(&self) -> Option<(&K, &V)> {
if self.len() > 0 {
......@@ -396,18 +280,6 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
}
/// Removes the last entry.
///
/// # Examples
///
/// ```
/// use linked_hash_map::LinkedHashMap;
/// let mut map = LinkedHashMap::new();
/// map.insert(1, 10);
/// map.insert(2, 20);
/// map.pop_back();
/// assert_eq!(map.get(&1), Some(&10));
/// assert_eq!(map.get(&2), None);
/// ```
#[inline]
pub fn pop_back(&mut self) -> Option<(K, V)> {
if self.len() > 0 {
......@@ -421,16 +293,6 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
}
/// Gets the last entry.
///
/// # Examples
///
/// ```
/// use linked_hash_map::LinkedHashMap;
/// let mut map = LinkedHashMap::new();
/// map.insert(1, 10);
/// map.insert(2, 20);
/// assert_eq!(map.back(), Some((&2, &20)));
/// ```
#[inline]
pub fn back(&mut self) -> Option<(&K, &V)> {
if self.len() > 0 {
......@@ -461,22 +323,6 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
/// Returns a double-ended iterator visiting all key-value pairs in order of insertion.
/// Iterator element type is `(&'a K, &'a V)`
///
/// # Examples
/// ```
/// use linked_hash_map::LinkedHashMap;
///
/// let mut map = LinkedHashMap::new();
/// map.insert("a", 10);
/// map.insert("c", 30);
/// map.insert("b", 20);
///
/// let mut iter = map.iter();
/// assert_eq!((&"a", &10), iter.next().unwrap());
/// assert_eq!((&"c", &30), iter.next().unwrap());
/// assert_eq!((&"b", &20), iter.next().unwrap());
/// assert_eq!(None, iter.next());
/// ```
pub fn iter(&self) -> Iter<K, V> {
let head = if ! self.head.is_null() {
unsafe { (*self.head).prev }
......@@ -493,24 +339,6 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
/// Returns a double-ended iterator visiting all key-value pairs in order of insertion.
/// Iterator element type is `(&'a K, &'a mut V)`
/// # Examples
/// ```
/// use linked_hash_map::LinkedHashMap;
///
/// let mut map = LinkedHashMap::new();
/// map.insert("a", 10);
/// map.insert("c", 30);
/// map.insert("b", 20);
///
/// {
/// let mut iter = map.iter_mut();
/// let mut entry = iter.next().unwrap();
/// assert_eq!(&"a", entry.0);
/// *entry.1 = 17;
/// }
///
/// assert_eq!(&17, map.get(&"a").unwrap());
/// ```
pub fn iter_mut(&mut self) -> IterMut<K, V> {
let head = if ! self.head.is_null() {
unsafe { (*self.head).prev }
......@@ -526,22 +354,6 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
}
/// Returns a double-ended iterator visiting all key in order of insertion.
///
/// # Examples
/// ```
/// use linked_hash_map::LinkedHashMap;
///
/// let mut map = LinkedHashMap::new();
/// map.insert('a', 10);
/// map.insert('c', 30);
/// map.insert('b', 20);
///
/// let mut keys = map.keys();
/// assert_eq!(&'a', keys.next().unwrap());
/// assert_eq!(&'c', keys.next().unwrap());
/// assert_eq!(&'b', keys.next().unwrap());
/// assert_eq!(None, keys.next());
/// ```
pub fn keys<'a>(&'a self) -> Keys<'a, K, V> {
fn first<A, B>((a, _): (A, B)) -> A { a }
let first: fn((&'a K, &'a V)) -> &'a K = first; // coerce to fn ptr
......@@ -550,22 +362,6 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
}
/// Returns a double-ended iterator visiting all values in order of insertion.
///
/// # Examples
/// ```
/// use linked_hash_map::LinkedHashMap;
///
/// let mut map = LinkedHashMap::new();
/// map.insert('a', 10);
/// map.insert('c', 30);
/// map.insert('b', 20);
///
/// let mut values = map.values();
/// assert_eq!(&10, values.next().unwrap());
/// assert_eq!(&30, values.next().unwrap());
/// assert_eq!(&20, values.next().unwrap());
/// assert_eq!(None, values.next());
/// ```
pub fn values<'a>(&'a self) -> Values<'a, K, V> {
fn second<A, B>((_, b): (A, B)) -> B { b }
let second: fn((&'a K, &'a V)) -> &'a V = second; // coerce to fn ptr
......
......@@ -12,30 +12,6 @@
//! capacity of the cache is exceeded, the least-recently-used
//! (where "used" means a look-up or putting the pair into the cache)
//! pair is automatically removed.
//!
//! # Examples
//!
//! ```
//! use lru_cache::LruCache;
//!
//! let mut cache = LruCache::new(2);
//!
//! cache.insert(1, 10);
//! cache.insert(2, 20);
//! cache.insert(3, 30);
//! assert!(cache.get_mut(&1).is_none());
//! assert_eq!(*cache.get_mut(&2).unwrap(), 20);
//! assert_eq!(*cache.get_mut(&3).unwrap(), 30);
//!
//! cache.insert(2, 22);
//! assert_eq!(*cache.get_mut(&2).unwrap(), 22);
//!
//! cache.insert(6, 60);
//! assert!(cache.get_mut(&3).is_none());
//!
//! cache.set_capacity(1);
//! assert!(cache.get_mut(&2).is_none());
//! ```
use std::collections::hash_map::RandomState;
use std::fmt;
......@@ -54,13 +30,6 @@ pub struct LruCache<K, V, S = RandomState> where K: Eq + Hash, S: BuildHasher {
impl<K: Hash + Eq, V> LruCache<K, V> {
/// Creates an empty cache that can hold at most `capacity` items.
///
/// # Examples
///
/// ```
/// use lru_cache::LruCache;
/// let mut cache: LruCache<i32, &str> = LruCache::new(10);
/// ```
pub fn new(capacity: usize) -> LruCache<K, V> {
LruCache {
map: LinkedHashMap::new(),
......@@ -76,17 +45,6 @@ impl<K, V, S> LruCache<K, V, S> where K: Eq + Hash, S: BuildHasher {
}
/// Checks if the map contains the given key.
///
/// # Examples
///
/// ```
/// use lru_cache::LruCache;
///
/// let mut cache = LruCache::new(1);
///
/// cache.insert(1, "a");
/// assert_eq!(cache.contains_key(&1), true);
/// ```
pub fn contains_key<Q: ?Sized>(&mut self, key: &Q) -> bool
where K: Borrow<Q>,
Q: Hash + Eq
......@@ -96,19 +54,6 @@ impl<K, V, S> LruCache<K, V, S> where K: Eq + Hash, S: BuildHasher {
/// Inserts a key-value pair into the cache. If the key already existed, the old value is
/// returned.
///
/// # Examples
///
/// ```
/// use lru_cache::LruCache;
///
/// let mut cache = LruCache::new(2);
///
/// cache.insert(1, "a");
/// cache.insert(2, "b");
/// assert_eq!(cache.get_mut(&1), Some(&mut "a"));
/// assert_eq!(cache.get_mut(&2), Some(&mut "b"));
/// ```
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
let old_val = self.map.insert(k, v);
if self.len() > self.capacity() {
......@@ -119,22 +64,6 @@ impl<K, V, S> LruCache<K, V, S> where K: Eq + Hash, S: BuildHasher {
/// Returns a mutable reference to the value corresponding to the given key in the cache, if
/// any.
///
/// # Examples
///
/// ```
/// use lru_cache::LruCache;
///
/// let mut cache = LruCache::new(2);
///
/// cache.insert(1, "a");
/// cache.insert(2, "b");
/// cache.insert(2, "c");
/// cache.insert(3, "d");
///
/// assert_eq!(cache.get_mut(&1), None);
/// assert_eq!(cache.get_mut(&2), Some(&mut "c"));
/// ```
pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
where K: Borrow<Q>,
Q: Hash + Eq
......@@ -143,21 +72,6 @@ impl<K, V, S> LruCache<K, V, S> where K: Eq + Hash, S: BuildHasher {
}
/// Removes the given key from the cache and returns its corresponding value.
///
/// # Examples
///
/// ```
/// use lru_cache::LruCache;
///
/// let mut cache = LruCache::new(2);
///
/// cache.insert(2, "a");
///
/// assert_eq!(cache.remove(&1), None);
/// assert_eq!(cache.remove(&2), Some("a"));
/// assert_eq!(cache.remove(&2), None);
/// assert_eq!(cache.len(), 0);
/// ```
pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
where K: Borrow<Q>,
Q: Hash + Eq
......@@ -166,50 +80,12 @@ impl<K, V, S> LruCache<K, V, S> where K: Eq + Hash, S: BuildHasher {
}
/// Returns the maximum number of key-value pairs the cache can hold.
///
/// # Examples
///
/// ```
/// use lru_cache::LruCache;
/// let mut cache: LruCache<i32, &str> = LruCache::new(2);
/// assert_eq!(cache.capacity(), 2);
/// ```
pub fn capacity(&self) -> usize {
self.max_size
}
/// Sets the number of key-value pairs the cache can hold. Removes
/// least-recently-used key-value pairs if necessary.
///
/// # Examples
///
/// ```
/// use lru_cache::LruCache;
///
/// let mut cache = LruCache::new(2);
///
/// cache.insert(1, "a");
/// cache.insert(2, "b");
/// cache.insert(3, "c");
///
/// assert_eq!(cache.get_mut(&1), None);
/// assert_eq!(cache.get_mut(&2), Some(&mut "b"));
/// assert_eq!(cache.get_mut(&3), Some(&mut "c"));
///
/// cache.set_capacity(3);
/// cache.insert(1, "a");
/// cache.insert(2, "b");
///
/// assert_eq!(cache.get_mut(&1), Some(&mut "a"));
/// assert_eq!(cache.get_mut(&2), Some(&mut "b"));
/// assert_eq!(cache.get_mut(&3), Some(&mut "c"));
///
/// cache.set_capacity(1);
///
/// assert_eq!(cache.get_mut(&1), None);
/// assert_eq!(cache.get_mut(&2), None);
/// assert_eq!(cache.get_mut(&3), Some(&mut "c"));
/// ```
pub fn set_capacity(&mut self, capacity: usize) {
for _ in capacity..self.len() {
self.remove_lru();
......@@ -234,52 +110,12 @@ impl<K, V, S> LruCache<K, V, S> where K: Eq + Hash, S: BuildHasher {
/// Returns an iterator over the cache's key-value pairs in least- to most-recently-used order.
///
/// Accessing the cache through the iterator does _not_ affect the cache's LRU state.
///
/// # Examples
///
/// ```
/// use lru_cache::LruCache;
///
/// let mut cache = LruCache::new(2);
///
/// cache.insert(1, 10);
/// cache.insert(2, 20);
/// cache.insert(3, 30);
///
/// let kvs: Vec<_> = cache.iter().collect();
/// assert_eq!(kvs, [(&2, &20), (&3, &30)]);
/// ```
pub fn iter(&self) -> Iter<K, V> { Iter(self.map.iter()) }
/// Returns an iterator over the cache's key-value pairs in least- to most-recently-used order,
/// with mutable references to the values.
///
/// Accessing the cache through the iterator does _not_ affect the cache's LRU state.
///
/// # Examples
///
/// ```
/// use lru_cache::LruCache;
///
/// let mut cache = LruCache::new(2);
///
/// cache.insert(1, 10);
/// cache.insert(2, 20);
/// cache.insert(3, 30);
///
/// let mut n = 2;
///
/// for (k, v) in cache.iter_mut() {
/// assert_eq!(*k, n);
/// assert_eq!(*v, n * 10);
/// *v *= 10;
/// n += 1;
/// }
///
/// assert_eq!(n, 4);
/// assert_eq!(cache.get_mut(&2), Some(&mut 200));
/// assert_eq!(cache.get_mut(&3), Some(&mut 300));
/// ```
pub fn iter_mut(&mut self) -> IterMut<K, V> { IterMut(self.map.iter_mut()) }
}
......
use std::{cmp, ptr};
use syscall::error::Result;
use BLOCK_SIZE;
use disk::Disk;
use self::lru_cache::LruCache;
......@@ -16,14 +17,14 @@ fn copy_memory(src: &[u8], dest: &mut [u8]) -> usize {
pub struct DiskCache<T> {
inner: T,
cache: LruCache<u64, [u8; 512]>,
cache: LruCache<u64, [u8; BLOCK_SIZE as usize]>,
}
impl<T: Disk> DiskCache<T> {
pub fn new(inner: T) -> Self {
DiskCache {
inner: inner,
cache: LruCache::new(65536) // 32 MB cache
cache: LruCache::new((256 * 1024 * 1024 / BLOCK_SIZE) as usize) // 256 MB cache
}
}
}
......@@ -34,11 +35,11 @@ impl<T: Disk> Disk for DiskCache<T> {
let mut read = 0;
let mut failed = false;
for i in 0..(buffer.len() + 511)/512 {
for i in 0..(buffer.len() + BLOCK_SIZE as usize - 1)/(BLOCK_SIZE as usize) {
let block_i = block + i as u64;
let buffer_i = i * 512;
let buffer_j = cmp::min(buffer_i + 512, buffer.len());
let buffer_i = i * BLOCK_SIZE as usize;
let buffer_j = cmp::min(buffer_i + BLOCK_SIZE as usize, buffer.len());
let buffer_slice = &mut buffer[buffer_i .. buffer_j];
if let Some(cache_buf) = self.cache.get_mut(&block_i) {
......@@ -53,14 +54,14 @@ impl<T: Disk> Disk for DiskCache<T> {
self.inner.read_at(block, buffer)?;
read = 0;
for i in 0..(buffer.len() + 511)/512 {
for i in 0..(buffer.len() + BLOCK_SIZE as usize - 1)/(BLOCK_SIZE as usize) {
let block_i = block + i as u64;
let buffer_i = i * 512;
let buffer_j = cmp::min(buffer_i + 512, buffer.len());
let buffer_i = i * BLOCK_SIZE as usize;
let buffer_j = cmp::min(buffer_i + BLOCK_SIZE as usize, buffer.len());
let buffer_slice = &buffer[buffer_i .. buffer_j];
let mut cache_buf = [0; 512];
let mut cache_buf = [0; BLOCK_SIZE as usize];
read += copy_memory(buffer_slice, &mut cache_buf);
self.cache.insert(block_i, cache_buf);
}
......@@ -75,14 +76,14 @@ impl<T: Disk> Disk for DiskCache<T> {
self.inner.write_at(block, buffer)?;
let mut written = 0;
for i in 0..(buffer.len() + 511)/512 {
for i in 0..(buffer.len() + BLOCK_SIZE as usize - 1)/(BLOCK_SIZE as usize) {
let block_i = block + i as u64;
let buffer_i = i * 512;
let buffer_j = cmp::min(buffer_i + 512, buffer.len());
let buffer_i = i * BLOCK_SIZE as usize;
let buffer_j = cmp::min(buffer_i + BLOCK_SIZE as usize, buffer.len());
let buffer_slice = &buffer[buffer_i .. buffer_j];
let mut cache_buf = [0; 512];
let mut cache_buf = [0; BLOCK_SIZE as usize];
written += copy_memory(buffer_slice, &mut cache_buf);
self.cache.insert(block_i, cache_buf);
}
......
......@@ -2,6 +2,7 @@ use std::fs::{File, OpenOptions};
use std::io::{Read, Write, Seek, SeekFrom};
use syscall::error::{Error, Result, EIO};
use BLOCK_SIZE;
use disk::Disk;
macro_rules! try_disk {
......@@ -37,13 +38,13 @@ impl DiskFile {
impl Disk for DiskFile {
fn read_at(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize> {
try_disk!(self.file.seek(SeekFrom::Start(block * 512)));
try_disk!(self.file.seek(SeekFrom::Start(block * BLOCK_SIZE)));
let count = try_disk!(self.file.read(buffer));
Ok(count)
}
fn write_at(&mut self, block: u64, buffer: &[u8]) -> Result<usize> {
try_disk!(self.file.seek(SeekFrom::Start(block * 512)));
try_disk!(self.file.seek(SeekFrom::Start(block * BLOCK_SIZE)));
let count = try_disk!(self.file.write(buffer));