Skip to content

Commit

Permalink
[collections] Add storage indexed map #440 (#441)
Browse files Browse the repository at this point in the history
* Update collections.rs

* Update indexed_map.rs

* Create indexed_map_impl.rs

* Create indexed_map_storage.rs
michaelvlach authored Feb 8, 2023
1 parent c49a79b commit e2e0a8f
Showing 4 changed files with 402 additions and 74 deletions.
1 change: 1 addition & 0 deletions src/agdb/collections.rs
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ pub mod bit_set;
pub mod dictionary;
pub mod dictionary_storage;
pub mod indexed_map;
pub mod indexed_map_storage;
pub mod map_storage;
pub mod multi_map;
pub mod multi_map_storage;
154 changes: 80 additions & 74 deletions src/agdb/collections/indexed_map.rs
Original file line number Diff line number Diff line change
@@ -1,91 +1,63 @@
use std::collections::hash_map::Iter;
use std::collections::HashMap;
pub mod indexed_map_impl;

use self::indexed_map_impl::IndexedMapImpl;
use super::map::map_data_memory::MapDataMemory;
use super::map::map_impl::MapImpl;
use super::map::multi_map_impl::MultiMapImpl;
use crate::utilities::stable_hash::StableHash;
use std::hash::Hash;
use std::marker::PhantomData;

struct IndexedMap<K, T>
where
K: PartialEq + Eq + Hash + Clone,
T: PartialEq + Eq + Hash + Clone,
{
keys_to_values: HashMap<K, T>,
values_to_keys: HashMap<T, K>,
}
pub type IndexedMap<K, T> = IndexedMapImpl<K, T, MapDataMemory<K, T>, MapDataMemory<T, K>>;

#[allow(dead_code)]
impl<K, T> IndexedMap<K, T>
where
K: PartialEq + Eq + Hash + Clone,
T: PartialEq + Eq + Hash + Clone,
K: Clone + Default + Eq + Hash + PartialEq + StableHash,
T: Clone + Default + Eq + Hash + PartialEq + StableHash,
{
pub fn insert(&mut self, key: &K, value: &T) {
self.keys_to_values.insert((*key).clone(), (*value).clone());
self.values_to_keys.insert((*value).clone(), (*key).clone());
}

pub fn iter(&self) -> Iter<K, T> {
self.keys_to_values.iter()
}

pub fn key(&self, value: &T) -> Option<&K> {
self.values_to_keys.get(value)
}

pub fn new() -> Self {
Self {
keys_to_values: HashMap::<K, T>::new(),
values_to_keys: HashMap::<T, K>::new(),
keys_to_values: MapImpl {
multi_map: MultiMapImpl {
data: MapDataMemory::<K, T>::new(),
phantom_marker: PhantomData,
},
},
values_to_keys: MapImpl {
multi_map: MultiMapImpl {
data: MapDataMemory::<T, K>::new(),
phantom_marker: PhantomData,
},
},
}
}

pub fn remove_key(&mut self, key: &K) {
if let Some(value) = self.keys_to_values.get(key) {
self.values_to_keys.remove(value);
}

self.keys_to_values.remove(key);
}

pub fn remove_value(&mut self, value: &T) {
if let Some(key) = self.values_to_keys.get(value) {
self.keys_to_values.remove(key);
}

self.values_to_keys.remove(value);
}

pub fn value(&self, key: &K) -> Option<&T> {
self.keys_to_values.get(key)
}
}

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

#[test]
fn new() {
let _ = IndexedMap::<u64, u64>::new();
}

#[test]
fn insert() {
let mut map = IndexedMap::<String, u64>::new();
let key = "alias".to_string();
let value = 1_u64;
map.insert(&key, &value);

assert_eq!(map.value(&key), Some(&value));
assert_eq!(map.key(&value), Some(&key));
assert_eq!(map.insert(&key, &value), Ok(()));

assert_eq!(map.value(&key), Ok(Some(value)));
assert_eq!(map.key(&value), Ok(Some(key)));
}

#[test]
fn iter() {
let mut map = IndexedMap::<String, u64>::new();
map.insert(&"alias1".to_string(), &1_u64);
map.insert(&"alias2".to_string(), &2_u64);
map.insert(&"alias3".to_string(), &3_u64);
assert_eq!(map.insert(&"alias1".to_string(), &1_u64), Ok(()));
assert_eq!(map.insert(&"alias2".to_string(), &2_u64), Ok(()));
assert_eq!(map.insert(&"alias3".to_string(), &3_u64), Ok(()));

let mut values = Vec::<(&String, &u64)>::new();
let mut values = Vec::<(String, u64)>::new();

for key_value in map.iter() {
values.push(key_value);
@@ -96,42 +68,76 @@ mod tests {
assert_eq!(
values,
vec![
(&"alias1".to_string(), &1_u64),
(&"alias2".to_string(), &2_u64),
(&"alias3".to_string(), &3_u64)
("alias1".to_string(), 1_u64),
("alias2".to_string(), 2_u64),
("alias3".to_string(), 3_u64)
]
);
}

#[test]
fn replace_by_key() {
let mut map = IndexedMap::<String, u64>::new();
let key = "alias".to_string();
let value = 1_u64;
let new_value = 2_u64;

assert_eq!(map.insert(&key, &value), Ok(()));
assert_eq!(map.insert(&key, &new_value), Ok(()));

assert_eq!(map.value(&key), Ok(Some(new_value)));
assert_eq!(map.key(&new_value), Ok(Some(key)));
assert_eq!(map.key(&value), Ok(None));
}

#[test]
fn replace_by_value() {
let mut map = IndexedMap::<String, u64>::new();
let key = "alias".to_string();
let new_key = "new_alias".to_string();
let value = 1_u64;

assert_eq!(map.insert(&key, &value), Ok(()));
assert_eq!(map.insert(&new_key, &value), Ok(()));

assert_eq!(map.value(&key), Ok(None));
assert_eq!(map.value(&new_key), Ok(Some(value)));
assert_eq!(map.key(&value), Ok(Some(new_key)));
}

#[test]
fn remove_key() {
let mut map = IndexedMap::<String, u64>::new();
let key = "alias".to_string();
let value = 1_u64;
map.insert(&key, &value);

assert_eq!(map.value(&key), Some(&value));
assert_eq!(map.key(&value), Some(&key));
assert_eq!(map.insert(&key, &value), Ok(()));

map.remove_key(&key);
assert_eq!(map.value(&key), Ok(Some(value)));
assert_eq!(map.key(&value), Ok(Some(key.clone())));

assert_eq!(map.value(&key), None);
assert_eq!(map.key(&value), None);
map.remove_key(&key).unwrap();
map.remove_key(&key).unwrap();

assert_eq!(map.value(&key), Ok(None));
assert_eq!(map.key(&value), Ok(None));
}

#[test]
fn remove_value() {
let mut map = IndexedMap::<String, u64>::new();
let key = "alias".to_string();
let value = 1_u64;
map.insert(&key, &value);

assert_eq!(map.value(&key), Some(&value));
assert_eq!(map.key(&value), Some(&key));
assert_eq!(map.insert(&key, &value), Ok(()));

assert_eq!(map.value(&key), Ok(Some(value)));
assert_eq!(map.key(&value), Ok(Some(key.clone())));

map.remove_value(&value);
map.remove_value(&value).unwrap();
map.remove_value(&value).unwrap();

assert_eq!(map.value(&key), None);
assert_eq!(map.key(&value), None);
assert_eq!(map.value(&key), Ok(None));
assert_eq!(map.key(&value), Ok(None));
}
}
66 changes: 66 additions & 0 deletions src/agdb/collections/indexed_map/indexed_map_impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use crate::collections::map::map_data::MapData;
use crate::collections::map::map_impl::MapImpl;
use crate::collections::map::map_iterator::MapIterator;
use crate::utilities::stable_hash::StableHash;
use crate::DbError;
use std::hash::Hash;

pub struct IndexedMapImpl<K, T, DataKT, DataTK>
where
K: Default + Eq + Hash + PartialEq + StableHash,
T: Default + Eq + Hash + PartialEq + StableHash,
DataKT: MapData<K, T>,
DataTK: MapData<T, K>,
{
pub(crate) keys_to_values: MapImpl<K, T, DataKT>,
pub(crate) values_to_keys: MapImpl<T, K, DataTK>,
}

#[allow(dead_code)]
impl<K, T, DataKT, DataTK> IndexedMapImpl<K, T, DataKT, DataTK>
where
K: Default + Eq + Hash + PartialEq + StableHash,
T: Default + Eq + Hash + PartialEq + StableHash,
DataKT: MapData<K, T>,
DataTK: MapData<T, K>,
{
pub fn insert(&mut self, key: &K, value: &T) -> Result<(), DbError> {
if let Some(v) = self.keys_to_values.insert(key, value)? {
self.values_to_keys.remove(&v)?;
}

if let Some(k) = self.values_to_keys.insert(value, key)? {
self.keys_to_values.remove(&k)?;
}

Ok(())
}

pub fn iter(&self) -> MapIterator<K, T, DataKT> {
self.keys_to_values.iter()
}

pub fn key(&self, value: &T) -> Result<Option<K>, DbError> {
self.values_to_keys.value(value)
}

pub fn remove_key(&mut self, key: &K) -> Result<(), DbError> {
if let Some(value) = self.keys_to_values.value(key)? {
self.values_to_keys.remove(&value)?;
}

self.keys_to_values.remove(key)
}

pub fn remove_value(&mut self, value: &T) -> Result<(), DbError> {
if let Some(key) = self.values_to_keys.value(value)? {
self.keys_to_values.remove(&key)?;
}

self.values_to_keys.remove(value)
}

pub fn value(&self, key: &K) -> Result<Option<T>, DbError> {
self.keys_to_values.value(key)
}
}
255 changes: 255 additions & 0 deletions src/agdb/collections/indexed_map_storage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
use super::indexed_map::indexed_map_impl::IndexedMapImpl;
use super::indexed_map::IndexedMap;
use super::map::map_data_memory::MapDataMemory;
use super::map::map_data_storage::MapDataStorage;
use super::map::map_impl::MapImpl;
use super::map::multi_map_impl::MultiMapImpl;
use super::map_storage::MapStorage;
use crate::storage::file_storage::FileStorage;
use crate::storage::storage_index::StorageIndex;
use crate::storage::storage_value::StorageValue;
use crate::storage::Storage;
use crate::utilities::stable_hash::StableHash;
use crate::DbError;
use std::cell::RefCell;
use std::hash::Hash;
use std::marker::PhantomData;
use std::rc::Rc;

type IndexedMapStorage<K, T, Data = FileStorage> =
IndexedMapImpl<K, T, MapDataStorage<K, T, Data>, MapDataStorage<T, K, Data>>;

#[allow(dead_code)]
impl<K, T, Data> IndexedMapStorage<K, T, Data>
where
K: Clone + Default + Eq + Hash + PartialEq + StableHash + StorageValue,
T: Clone + Default + Eq + Hash + PartialEq + StableHash + StorageValue,
Data: Storage,
{
pub fn new(storage: Rc<RefCell<Data>>) -> Result<Self, DbError> {
let keys_to_values = MapStorage::<K, T, Data>::new(storage.clone())?;
let values_to_keys = MapStorage::<T, K, Data>::new(storage)?;

Ok(Self {
keys_to_values,
values_to_keys,
})
}

pub fn from_storage(
storage: Rc<RefCell<Data>>,
index: &(StorageIndex, StorageIndex),
) -> Result<Self, DbError> {
let keys_to_values = MapStorage::<K, T, Data>::from_storage(storage.clone(), &index.0)?;
let values_to_keys = MapStorage::<T, K, Data>::from_storage(storage, &index.1)?;

Ok(Self {
keys_to_values,
values_to_keys,
})
}

pub fn storage_index(&self) -> (StorageIndex, StorageIndex) {
(
self.keys_to_values.storage_index(),
self.values_to_keys.storage_index(),
)
}

pub fn to_indexed_map(&self) -> Result<IndexedMap<K, T>, DbError> {
let mut keys_to_values = MapImpl::<K, T, MapDataMemory<K, T>> {
multi_map: MultiMapImpl {
data: MapDataMemory::<K, T>::new(),
phantom_marker: PhantomData,
},
};

for (key, value) in self.keys_to_values.iter() {
keys_to_values.insert(&key, &value)?;
}

let mut values_to_keys = MapImpl::<T, K, MapDataMemory<T, K>> {
multi_map: MultiMapImpl {
data: MapDataMemory::<T, K>::new(),
phantom_marker: PhantomData,
},
};

for (key, value) in self.values_to_keys.iter() {
values_to_keys.insert(&key, &value)?;
}

Ok(IndexedMap {
keys_to_values,
values_to_keys,
})
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::test_utilities::test_file::TestFile;

#[test]
fn from_storage() {
let test_file = TestFile::new();
let storage = Rc::new(RefCell::new(
FileStorage::new(test_file.file_name()).unwrap(),
));

let index;

{
let mut map = IndexedMapStorage::<String, u64>::new(storage.clone()).unwrap();
let key = "alias".to_string();
let value = 1_u64;
map.insert(&key, &value).unwrap();
index = map.storage_index();
}

let map = IndexedMapStorage::<String, u64>::from_storage(storage, &index).unwrap();
assert_eq!(map.value(&"alias".to_string()).unwrap(), Some(1_u64));
}

#[test]
fn to_indexed_map() {
let test_file = TestFile::new();
let storage = Rc::new(RefCell::new(
FileStorage::new(test_file.file_name()).unwrap(),
));
let mut map = IndexedMapStorage::<String, u64>::new(storage).unwrap();
map.insert(&"alias".to_string(), &1_u64).unwrap();

let mem_map = map.to_indexed_map().unwrap();

assert_eq!(mem_map.value(&"alias".to_string()).unwrap(), Some(1_u64));
}

#[test]
fn insert() {
let test_file = TestFile::new();
let storage = Rc::new(RefCell::new(
FileStorage::new(test_file.file_name()).unwrap(),
));
let mut map = IndexedMapStorage::<String, u64>::new(storage).unwrap();
let key = "alias".to_string();
let value = 1_u64;

assert_eq!(map.insert(&key, &value), Ok(()));

assert_eq!(map.value(&key), Ok(Some(value)));
assert_eq!(map.key(&value), Ok(Some(key)));
}

#[test]
fn iter() {
let test_file = TestFile::new();
let storage = Rc::new(RefCell::new(
FileStorage::new(test_file.file_name()).unwrap(),
));
let mut map = IndexedMapStorage::<String, u64>::new(storage).unwrap();
assert_eq!(map.insert(&"alias1".to_string(), &1_u64), Ok(()));
assert_eq!(map.insert(&"alias2".to_string(), &2_u64), Ok(()));
assert_eq!(map.insert(&"alias3".to_string(), &3_u64), Ok(()));

let mut values = Vec::<(String, u64)>::new();

for key_value in map.iter() {
values.push(key_value);
}

values.sort();

assert_eq!(
values,
vec![
("alias1".to_string(), 1_u64),
("alias2".to_string(), 2_u64),
("alias3".to_string(), 3_u64)
]
);
}

#[test]
fn replace_by_key() {
let test_file = TestFile::new();
let storage = Rc::new(RefCell::new(
FileStorage::new(test_file.file_name()).unwrap(),
));
let mut map = IndexedMapStorage::<String, u64>::new(storage).unwrap();
let key = "alias".to_string();
let value = 1_u64;
let new_value = 2_u64;

assert_eq!(map.insert(&key, &value), Ok(()));
assert_eq!(map.insert(&key, &new_value), Ok(()));

assert_eq!(map.value(&key), Ok(Some(new_value)));
assert_eq!(map.key(&new_value), Ok(Some(key)));
assert_eq!(map.key(&value), Ok(None));
}

#[test]
fn replace_by_value() {
let test_file = TestFile::new();
let storage = Rc::new(RefCell::new(
FileStorage::new(test_file.file_name()).unwrap(),
));
let mut map = IndexedMapStorage::<String, u64>::new(storage).unwrap();
let key = "alias".to_string();
let new_key = "new_alias".to_string();
let value = 1_u64;

assert_eq!(map.insert(&key, &value), Ok(()));
assert_eq!(map.insert(&new_key, &value), Ok(()));

assert_eq!(map.value(&key), Ok(None));
assert_eq!(map.value(&new_key), Ok(Some(value)));
assert_eq!(map.key(&value), Ok(Some(new_key)));
}

#[test]
fn remove_key() {
let test_file = TestFile::new();
let storage = Rc::new(RefCell::new(
FileStorage::new(test_file.file_name()).unwrap(),
));
let mut map = IndexedMapStorage::<String, u64>::new(storage).unwrap();
let key = "alias".to_string();
let value = 1_u64;

assert_eq!(map.insert(&key, &value), Ok(()));

assert_eq!(map.value(&key), Ok(Some(value)));
assert_eq!(map.key(&value), Ok(Some(key.clone())));

map.remove_key(&key).unwrap();
map.remove_key(&key).unwrap();

assert_eq!(map.value(&key), Ok(None));
assert_eq!(map.key(&value), Ok(None));
}

#[test]
fn remove_value() {
let test_file = TestFile::new();
let storage = Rc::new(RefCell::new(
FileStorage::new(test_file.file_name()).unwrap(),
));
let mut map = IndexedMapStorage::<String, u64>::new(storage).unwrap();
let key = "alias".to_string();
let value = 1_u64;

assert_eq!(map.insert(&key, &value), Ok(()));

assert_eq!(map.value(&key), Ok(Some(value)));
assert_eq!(map.key(&value), Ok(Some(key.clone())));

map.remove_value(&value).unwrap();
map.remove_value(&value).unwrap();

assert_eq!(map.value(&key), Ok(None));
assert_eq!(map.key(&value), Ok(None));
}
}

0 comments on commit e2e0a8f

Please sign in to comment.